diff --git a/.github/scripts/extract_matrix.py b/.github/scripts/extract_matrix.py index 7347eaae72..00c9683c12 100644 --- a/.github/scripts/extract_matrix.py +++ b/.github/scripts/extract_matrix.py @@ -68,6 +68,12 @@ "cpython-gate", "darwin", + + # python-graalos-resources downloads the GraalOS runtime from an Oracle-internal + # location (GRAALPY_GRAALOS_ARTIFACT_BASE_URL, an overlay import that is empty in the + # public ci.jsonnet) and python-resource-variants consumes that artifact. Both fail + # the same way in upstream's own GitHub Actions runs. + "graalos", ) DOWNLOADS_LINKS = { @@ -75,19 +81,27 @@ "ECLIPSE": "https://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops4/R-4.26-202211231800/eclipse-SDK-4.26-linux-gtk-x86_64.tar.gz" } -# Github Runners OSS +# Runner labels by required capabilities. Elide's fork builds and tests on its +# self-hosted runner pool, not on GitHub-hosted runners. +LINUX_AMD64_RUNNER = "linux-amd64-cipool" +LINUX_AARCH64_RUNNER = "linux-arm64-cipool" +WINDOWS_AMD64_RUNNER = "windows-amd64-cipool" OSS = { - "ubuntu-latest": ["linux", "amd64"], - "ubuntu-24.04-arm": ["linux", "aarch64"], - "windows-latest": ["windows", "amd64"] + LINUX_AMD64_RUNNER: ["linux", "amd64"], + LINUX_AARCH64_RUNNER: ["linux", "aarch64"], + WINDOWS_AMD64_RUNNER: ["windows", "amd64"] } # Override unavailable Python versions for some OS/Arch / job name combinations PYTHON_VERSIONS = { - "ubuntu-24.04-arm": "3.12.8", - "ubuntu-latest": "3.12.8", + LINUX_AARCH64_RUNNER: "3.12.8", + LINUX_AMD64_RUNNER: "3.12.8", "style-gate": "3.8.12", "style-ecj-gate": "3.8.12", + # The JUnit gates build a delvewheel venv, which needs CPython >= 3.12 (or an + # Oracle-internal ARTIFACT_DOWNLOAD_SCRIPT); ci.jsonnet's 3.8 fails there upstream as well. + "python-junit-gate-windows": "3.12.8", + "python-junit-maven-gate-windows": "3.12.8", } EXCLUDED_SYSTEM_PACKAGES = { @@ -119,7 +133,7 @@ def runs_on(self) -> str: for os, caps in OSS.items(): if all(required in capabilities for required in caps): return os - return "ubuntu-latest" + return LINUX_AMD64_RUNNER @cached_property def name(self) -> str: @@ -132,7 +146,7 @@ def targets(self) -> list[str]: @cached_property def env(self) -> dict[str, str]: environment = self.job.get("environment", {}) | DEFAULT_ENV - if self.runs_on == "windows-latest": + if self.runs_on == WINDOWS_AMD64_RUNNER: def _to_windows_env_format(s: str) -> str: # Replace ${VAR} and $VAR with %VAR% s = re.sub(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}", r"%\1%", s) @@ -180,7 +194,7 @@ def system_packages(self) -> list[str]: k = k[3:] if any(excluded in k for excluded in EXCLUDED_SYSTEM_PACKAGES): continue - system_packages.append(f"'{k}'" if self.runs_on != "windows-latest" else f"{k}") + system_packages.append(f"'{k}'" if self.runs_on != WINDOWS_AMD64_RUNNER else f"{k}") return system_packages @cached_property @@ -191,13 +205,13 @@ def python_packages(self) -> list[str]: key = k[4:] if key in PYTHON_PACKAGES_VERSIONS: continue python_packages.append(f"{key}{v}") - return [f"'{pkg}'" if self.runs_on != "windows-latest" else f"{pkg}" for pkg in python_packages] + return [f"'{pkg}'" if self.runs_on != WINDOWS_AMD64_RUNNER else f"{pkg}" for pkg in python_packages] def get_download_steps(self, key: str, version: str) -> str: download_link = self.get_download_link(key, version) filename = download_link.split('/')[-1] - if self.runs_on == "windows-latest": + if self.runs_on == WINDOWS_AMD64_RUNNER: return (f""" Invoke-WebRequest -Uri {download_link} -OutFile {filename} Expand-Archive -Path {filename} -DestinationPath . diff --git a/.github/workflows/_downstream-test-common.yml b/.github/workflows/_downstream-test-common.yml index 9d97ce7c52..4f7bbd85ee 100644 --- a/.github/workflows/_downstream-test-common.yml +++ b/.github/workflows/_downstream-test-common.yml @@ -29,10 +29,10 @@ jobs: fail-fast: false matrix: os: - - id: ubuntu-latest + - id: linux-amd64-cipool platform: linux arch: amd64 - - id: macos-latest + - id: macos-arm64-cipool platform: macos arch: aarch64 diff --git a/.github/workflows/_downstream-test-oracledb.yml b/.github/workflows/_downstream-test-oracledb.yml index 5e0717866b..b2104ca753 100644 --- a/.github/workflows/_downstream-test-oracledb.yml +++ b/.github/workflows/_downstream-test-oracledb.yml @@ -25,7 +25,7 @@ permissions: jobs: build-numpy-wheels: - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: numpy==2.2.6 steps: @@ -58,7 +58,7 @@ jobs: build-pandas-wheels: needs: build-numpy-wheels - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: pandas==2.2.3 PIP_FIND_LINKS: ${{ github.workspace }}/dependency-wheels @@ -99,7 +99,7 @@ jobs: build-pyarrow-wheels: needs: build-numpy-wheels - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool env: PACKAGES_TO_BUILD: pyarrow==20.0.0 PIP_FIND_LINKS: ${{ github.workspace }}/dependency-wheels @@ -163,7 +163,7 @@ jobs: fail-fast: false matrix: os: - - id: ubuntu-latest + - id: linux-amd64-cipool platform: linux arch: amd64 diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 082afd840c..d535bf735a 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -28,15 +28,12 @@ permissions: jobs: build_wheels: + # Elide's fork builds on its self-hosted runner pool, not on GitHub-hosted runners. runs-on: >- - ${{ contains(inputs.platform, 'self-hosted-linux-amd64') && fromJson('["self-hosted", "Linux", "X86"]') || - contains(inputs.platform, 'self-hosted-linux-aarch64') && fromJson('["self-hosted", "Linux", "ARM64"]') || - contains(inputs.platform, 'self-hosted-macos') && fromJson('["self-hosted", "macOS"]') || - contains(inputs.platform, 'self-hosted-windows') && fromJson('["self-hosted", "Windows"]') || - contains(inputs.platform, 'linux-amd64') && fromJson('["ubuntu-latest"]') || - contains(inputs.platform, 'linux-aarch64') && fromJson('["ubuntu-24.04-arm"]') || - contains(inputs.platform, 'windows') && fromJson('["windows-latest"]') || - contains(inputs.platform, 'macos') && fromJson('["macos-latest"]') }} + ${{ contains(inputs.platform, 'aarch64') && contains(inputs.platform, 'linux') && 'linux-arm64-cipool' || + contains(inputs.platform, 'linux') && 'linux-amd64-cipool' || + contains(inputs.platform, 'windows') && 'windows-amd64-cipool' || + contains(inputs.platform, 'macos') && 'macos-arm64-cipool' }} container: >- ${{ contains(inputs.platform, 'linux-amd64') && 'quay.io/pypa/manylinux_2_28_x86_64' || contains(inputs.platform, 'linux-aarch64') && 'quay.io/pypa/manylinux_2_28_aarch64' || diff --git a/.github/workflows/ci-matrix-gen.yml b/.github/workflows/ci-matrix-gen.yml index 8920a5c6b5..6b759207b7 100644 --- a/.github/workflows/ci-matrix-gen.yml +++ b/.github/workflows/ci-matrix-gen.yml @@ -82,6 +82,17 @@ jobs: matrix: include: ${{ fromJson(needs.generate-tier1.outputs.artifact_matrix) }} steps: &buildsteps + # The self-hosted runners keep their workspace between jobs, and these steps clone + # mx and other repositories next to the checkout, so start from an empty workspace. + - name: Clean workspace + if: runner.os != 'Windows' + shell: bash + run: find "${GITHUB_WORKSPACE:?}" -mindepth 1 -maxdepth 1 -exec rm -rf {} + + - name: Clean workspace (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: Get-ChildItem -Force -LiteralPath $env:GITHUB_WORKSPACE | Remove-Item -Recurse -Force + - name: Process matrix downloads if: ${{ matrix.downloads_steps }} run: | @@ -91,8 +102,13 @@ jobs: shell: bash if: runner.os != 'Windows' run: | + # A UTF-8 locale, as on GitHub's runners: the JDK uses it for file names (some CA + # certificates in /etc/ssl/certs have non-ASCII names). + if [ "$RUNNER_OS" = macOS ]; then echo "LANG=en_US.UTF-8" >> $GITHUB_ENV; echo "LC_ALL=en_US.UTF-8" >> $GITHUB_ENV; + else echo "LANG=C.UTF-8" >> $GITHUB_ENV; echo "LC_ALL=C.UTF-8" >> $GITHUB_ENV; fi matrix_env='${{ toJson(matrix.env) }}' - echo $matrix_env | jq -r 'to_entries[] | "\(.key)=\(.value)"' >> tmp.env + # python3 rather than jq, which the self-hosted runners don't all have. + echo $matrix_env | python3 -c 'import json, sys; [print(f"{k}={v}") for k, v in json.load(sys.stdin).items()]' >> tmp.env while IFS= read -r line; do eval "echo \"$line\"" >> $GITHUB_ENV done < tmp.env @@ -126,9 +142,31 @@ jobs: - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 - if: ${{ matrix.python_version }} + if: ${{ runner.os == 'Windows' && matrix.python_version }} with: python-version: ${{ matrix.python_version }} + # actions/setup-python only has interpreters for GitHub's own runner images, so on + # the self-hosted Linux and macOS runners the version comes from uv (python-build-standalone), + # in a virtualenv with pip that is put first on the PATH. + - name: Set up Python with uv + if: ${{ runner.os != 'Windows' && matrix.python_version }} + shell: bash + env: + UV_VERSION: 0.12.20 + PYTHON_VERSION: ${{ matrix.python_version }} + run: | + # Everything in the job's temp directory, and only uv-managed interpreters: the runners + # can have partial interpreters (and a shared uv cache) left by earlier jobs. + export UV_INSTALL_DIR="$RUNNER_TEMP/uv/bin" UV_PYTHON_INSTALL_DIR="$RUNNER_TEMP/uv/python" UV_NO_MODIFY_PATH=1 + export UV_CACHE_DIR="$RUNNER_TEMP/uv/cache" UV_LINK_MODE=copy UV_PYTHON_PREFERENCE=only-managed + # The temp directory survives between jobs on these runners: a partial interpreter from an + # earlier job would be reused ("Python installation is missing a _sysconfigdata_ file"). + rm -rf "$RUNNER_TEMP/uv" + curl -LsSf "https://astral.sh/uv/${UV_VERSION}/install.sh" | sh + rm -rf "$RUNNER_TEMP/python-venv" + "$UV_INSTALL_DIR/uv" venv --seed --python "$PYTHON_VERSION" "$RUNNER_TEMP/python-venv" + echo "$RUNNER_TEMP/python-venv/bin" >> "$GITHUB_PATH" + "$RUNNER_TEMP/python-venv/bin/python" --version - name: Install python packages on Unix if: ${{ runner.os != 'Windows' && matrix.python_packages }} run: | @@ -150,6 +188,19 @@ jobs: for pkg in ${{ matrix.system_packages }}; do sudo apt-get -qq install "$pkg" || true done + # apt failures are tolerated above, and on a self-hosted runner whose dpkg state is + # broken the maven package can be unpacked but unconfigured (no /usr/bin/mvn), so + # fall back to a direct Maven download when the job needs it and mvn is missing. + case " ${{ matrix.system_packages }} " in *"'maven'"*) + if ! command -v mvn >/dev/null; then + maven_version=3.9.9 + maven_dir="$RUNNER_TEMP/maven" + rm -rf "$maven_dir" && mkdir -p "$maven_dir" + curl -fsSL "https://archive.apache.org/dist/maven/maven-3/$maven_version/binaries/apache-maven-$maven_version-bin.tar.gz" | tar -xz -C "$maven_dir" + echo "$maven_dir/apache-maven-$maven_version/bin" >> "$GITHUB_PATH" + echo "Installed Maven $maven_version to $maven_dir (mvn was not on the PATH after apt-get)" + fi + ;; esac - name: Install system packages on macOS if: ${{ runner.os == 'macOS' && matrix.system_packages }} run: | @@ -162,12 +213,34 @@ jobs: if: ${{ runner.os == 'Windows' && matrix.system_packages }} run: | $packages = '${{ matrix.system_packages }}' -split ' ' + # The self-hosted Windows runners have no Chocolatey (and no preinstalled Maven, unlike + # GitHub's images), so Maven is downloaded directly when choco is missing; cmake is + # already on their PATH. + $haveChoco = [bool](Get-Command choco -ErrorAction SilentlyContinue) foreach ($pkg in $packages) { - try { - choco install $pkg -y - } catch { - Write-Host "Failed to install $pkg, skipping." - Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + if ($haveChoco) { + try { + choco install $pkg -y + } catch { + Write-Host "Failed to install $pkg, skipping." + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Yellow + } + } elseif ($pkg -eq 'maven' -and -not (Get-Command mvn -ErrorAction SilentlyContinue)) { + $mavenVersion = '3.9.9' + $mavenDir = Join-Path $env:RUNNER_TEMP 'maven' + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $mavenDir + New-Item -ItemType Directory -Force $mavenDir | Out-Null + $zip = Join-Path $mavenDir "apache-maven-$mavenVersion-bin.zip" + Invoke-WebRequest -Uri "https://archive.apache.org/dist/maven/maven-3/$mavenVersion/binaries/apache-maven-$mavenVersion-bin.zip" -OutFile $zip + Expand-Archive -Path $zip -DestinationPath $mavenDir + $mavenBin = Join-Path $mavenDir "apache-maven-$mavenVersion\bin" + $mavenBin | Out-File -FilePath $env:GITHUB_PATH -Append + # Not verified with `mvn --version` here: the JDK is only fetched in a later step. + Write-Host "Installed Maven $mavenVersion to $mavenBin" + } elseif (Get-Command $pkg -ErrorAction SilentlyContinue) { + Write-Host "$pkg is already available: $((Get-Command $pkg).Source)" + } else { + Write-Host "No choco on this runner and no fallback for $pkg, skipping." -ForegroundColor Yellow } } diff --git a/.github/workflows/ci-unittests.yml b/.github/workflows/ci-unittests.yml index 91035de4d8..11fcfc3e2a 100644 --- a/.github/workflows/ci-unittests.yml +++ b/.github/workflows/ci-unittests.yml @@ -11,15 +11,20 @@ permissions: jobs: abi-check: if: github.event.pull_request.draft == false - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install libabigail shell: bash run: | - sudo apt-get update - sudo apt-get install -y abigail-tools + # The self-hosted runners keep abigail-tools installed; only touch apt when it is + # missing, so a broken dpkg state left by another job's package install does not fail + # the check. + if ! command -v abidiff >/dev/null; then + sudo apt-get update + sudo apt-get install -y abigail-tools + fi - name: Get mx and labsjdk shell: bash diff --git a/.github/workflows/platforms-tests.yml b/.github/workflows/platforms-tests.yml index f0fea75886..2c2982b3ec 100644 --- a/.github/workflows/platforms-tests.yml +++ b/.github/workflows/platforms-tests.yml @@ -9,7 +9,7 @@ permissions: jobs: centos-ppc64le-test: - runs-on: ubuntu-latest + runs-on: linux-amd64-cipool steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/docs/site/_includes/compatibility.html b/docs/site/_includes/compatibility.html index 6c22511b7c..c2f273b10f 100644 --- a/docs/site/_includes/compatibility.html +++ b/docs/site/_includes/compatibility.html @@ -87,7 +87,7 @@ const parts = item.name.split('.'); const package_name = parts[0]; const version = parts.slice(1, -1).join('.') || DB.ANY_VERSION; - packages.push(`${package_name},${version},0,${BUILD_SCRIPT_AVAILABLE(item.html_url)}`); + packages.push(`${package_name},${version},,${BUILD_SCRIPT_AVAILABLE(item.html_url)}`); } resolve(packages.join("\n")); } else { @@ -116,7 +116,7 @@ patches.push( [currentPatch.name, currentPatch.version, - 0, + '', currentPatch.comment || PATCH_AVAILABLE].join(",") ) } @@ -143,7 +143,7 @@ patches.push( [currentPatch.name, currentPatch.version, - 0, + '', currentPatch.comment || PATCH_AVAILABLE].join(",") ) } @@ -285,11 +285,11 @@ load_db(graalpyModuleValue).then(function (db_contents) { database = new DB("python", db_contents); const rowsPerPage = getRowsPerPage(); - let count = 0; let countCompatible = 0; let countUntested = 0; let countIncompatible = 0; let countNotSupported = 0; + let tableRowCount = 0; $('#dataTable tbody').empty(); for (let package in database.db) { const versions = database.db[package]; @@ -300,7 +300,7 @@ if (versionA > versionB) return 1; return 0; }); - versions_loop: for (const version of version_keys) { + for (const version of version_keys) { if (version.startsWith('~')) { continue; } @@ -310,18 +310,16 @@ countCompatible++; break; case 1: - countUntested++; + countIncompatible++; break; case 2: - countIncompatible++; + countUntested++; break; case 3: countNotSupported++; break; - default: - continue versions_loop; } - const styling = count++ < rowsPerPage ? '' : ' style="display: none;"'; + const styling = tableRowCount++ < rowsPerPage ? '' : ' style="display: none;"'; const highlight = ''.repeat(Math.ceil(info.highlight)); $('#dataTable tbody').append(` @@ -332,6 +330,7 @@ } } $('#compatibility_page__search-field').trigger("input"); + const count = countCompatible + countUntested + countIncompatible + countNotSupported; updateStatistics(count, countCompatible, countUntested, countIncompatible, countNotSupported); updatePagination(true); }); @@ -543,15 +542,15 @@

Over 600 Python packages tested for compatibility
Compatible: loading...
+ title="More than 75% of the package's tests run successfully on GraalPy">Compatible: loading...
Currently Untested: loading...
Currently - Incompatible: loading...
+ title="Fewer than 75% of the package's tests run successfully on GraalPy">Currently + Failing Tests: loading...
Not Supported: loading...
diff --git a/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py new file mode 100644 index 0000000000..ecfc0455e3 --- /dev/null +++ b/graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py @@ -0,0 +1,164 @@ +# Copyright (c) 2017, 2026, Oracle and/or its affiliates. +# Copyright (c) 2013, Regents of the University of California +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of +# conditions and the following disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# micro benchmark: megamorphic attribute access inspired by richards + +iteration = 20000 + + +class TaskState(object): + pass + + +class Task(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task0(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task1(Task0): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task2(Task1): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task3(Task2): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task4(Task): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task5(Task4): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task6(Task5): + def __init__(self, foo): + Task.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task7(Task6): + def __init__(self, foo): + Task.__init__(self, foo) + + +class Task8(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task9(Task8): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task10(Task9): + def __init__(self, foo): + Task8.__init__(self, foo) + + +class Task11(Task10): + def __init__(self, foo): + Task8.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task12(TaskState): + def __init__(self, foo): + self.foo = foo + + +class Task13(Task12): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +class Task14(Task13): + def __init__(self, foo): + Task12.__init__(self, foo) + + +class Task15(Task14): + def __init__(self, foo): + Task12.__init__(self, foo) + self.bar = foo + 1 + self.baz = foo + 2 + + +TASK_LIST = [Task0(0), Task1(1), Task2(2), Task3(3), + Task4(4), Task5(5), Task6(6), Task7(7), + Task8(8), Task9(9), Task10(10), Task11(11), + Task12(12), Task13(13), Task14(14), Task15(15)] + + +def do_stuff(): + task_list = TASK_LIST + total = 0 + for i in range(iteration): + for t in task_list: + total = (total + t.foo) % 7 + + return total + + +def measure(num): + result = 0 + for i in range(num): # 50000 + result |= do_stuff() + + return result + + +def __benchmark__(num=1000): + return measure(num) + + +def run(): + __benchmark__(num=10) + diff --git a/graalpython/com.oracle.graal.python.cext/src/call.c b/graalpython/com.oracle.graal.python.cext/src/call.c index 954f70eed0..b6693f5af5 100644 --- a/graalpython/com.oracle.graal.python.cext/src/call.c +++ b/graalpython/com.oracle.graal.python.cext/src/call.c @@ -929,6 +929,31 @@ PyObject_VectorcallMethod(PyObject *name, PyObject *const *args, assert(args != NULL); assert(PyVectorcall_NARGS(nargsf) >= 1); + /* GraalPy change: Perform the method lookup and call in a single upcall if the receiver is + managed, or if a native extension type inherited GraalPy's managed object.__getattribute__ + slot. If the lookup finds an unbound native method descriptor, the upcall returns the + descriptor instead of invoking it. This keeps native extension method calls in native code + without duplicating managed MRO and instance-dict lookup semantics here. */ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (points_to_py_handle_space(args[0]) || + (Py_TYPE(args[0])->tp_getattro == PyBaseObject_Type.tp_getattro && PyUnicode_CheckExact(name))) { + PyObject *result = NULL; + int native_method = GraalPyPrivate_Object_VectorcallMethod(name, args[0], args + 1, + nargs - 1, kwnames, &result); + if (native_method <= 0) { + return result; + } + + /* The receiver is still args[0], so the descriptor can use the original argument array. + Do not expose PY_VECTORCALL_ARGUMENTS_OFFSET: the native callee must not modify the + slot immediately preceding args. */ + nargsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET; + PyObject *call_result = _PyObject_VectorcallTstate(_PyThreadState_GET(), result, + args, nargsf, kwnames); + Py_DECREF(result); + return call_result; + } + PyThreadState *tstate = _PyThreadState_GET(); PyObject *callable = NULL; /* Use args[0] as "self" argument */ diff --git a/graalpython/com.oracle.graal.python.cext/src/object.c b/graalpython/com.oracle.graal.python.cext/src/object.c index 4f6d29b17d..2a67cf1cf6 100644 --- a/graalpython/com.oracle.graal.python.cext/src/object.c +++ b/graalpython/com.oracle.graal.python.cext/src/object.c @@ -1645,6 +1645,14 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) } } + /* GraalPy change: Native extension types inherit GraalPy's managed + object.__getattribute__ slot rather than PyObject_GenericGetAttr. + Do the LOAD_METHOD-style lookup on the managed side so that method + descriptors stay unbound. */ + if (tp->tp_getattro == PyBaseObject_Type.tp_getattro && PyUnicode_CheckExact(name)) { + return GraalPyPrivate_Object_GetMethod(obj, name, method); + } + if (tp->tp_getattro != PyObject_GenericGetAttr || !PyUnicode_CheckExact(name)) { *method = PyObject_GetAttr(obj, name); return 0; diff --git a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java index dcc72a50c3..b082c7b78b 100644 --- a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java +++ b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java @@ -157,6 +157,7 @@ private static void appendDecodedChars(StringBuilder builder, CharBuffer out) { private boolean noUserSite = false; private boolean noSite = false; private boolean unbufferedIO = false; + private boolean legacyWindowsStdio = false; private boolean multiContext = false; private int repeatedRuns = 1; private boolean snaptshotStartup = false; @@ -794,6 +795,7 @@ protected void launch(Builder contextBuilder) { safePath = safePath || getBoolEnv("PYTHONSAFEPATH"); verboseFlag = verboseFlag || getBoolEnv("PYTHONVERBOSE"); unbufferedIO = unbufferedIO || getBoolEnv("PYTHONUNBUFFERED"); + legacyWindowsStdio = getBoolEnv("PYTHONLEGACYWINDOWSSTDIO"); dontWriteBytecode = dontWriteBytecode || getBoolEnv("PYTHONDONTWRITEBYTECODE"); String maxStrDigitsEnv = getEnv("PYTHONINTMAXSTRDIGITS"); if (intMaxStrDigits < 0 && maxStrDigitsEnv != null) { @@ -877,6 +879,9 @@ protected void launch(Builder contextBuilder) { } contextBuilder.option("python.IgnoreEnvironmentFlag", Boolean.toString(ignoreEnv)); contextBuilder.option("python.UnbufferedIO", Boolean.toString(unbufferedIO)); + if (IS_WINDOWS) { + contextBuilder.option("python.LegacyWindowsStdio", Boolean.toString(legacyWindowsStdio)); + } ConsoleHandler consoleHandler = createConsoleHandler(System.in, System.out); contextBuilder.arguments(getLanguageId(), programArgs.toArray(new String[programArgs.size()])); @@ -1288,6 +1293,7 @@ protected void printHelp(OptionCategory maxCategory) { "PYTHON_CPU_COUNT: override the return value of os.cpu_count() (-X cpu_count).\n" + "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n" + "PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n" + + "PYTHONLEGACYWINDOWSSTDIO: use legacy Windows console I/O.\n" + "PYTHONHASHSEED: if this variable is set to 'random', the effect is the same\n" + " as specifying the -R option: a random value is used to seed the hashes of\n" + " str, bytes and datetime objects. It can also be set to an integer\n" + diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java index f71fb33cf2..a795a5b3d3 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/SocketTests.java @@ -98,7 +98,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.graal.python.PythonLanguage; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -110,28 +109,28 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PosixConstants.MandatoryIntConstant; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.FamilySpecificSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.AcceptResult; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.FamilySpecificSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.InvalidAddressException; +import com.oracle.graal.python.runtime.PosixSupport.InvalidUnixSocketPathException; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RecvfromResult; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnixSockAddr; import com.oracle.graal.python.test.integration.CleanupRule; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.memory.ByteArraySupport; @@ -158,17 +157,11 @@ public static String[] params() { private static final byte[] DATA2 = new byte[]{4, 5, 6, 7}; private static final UnixSockAddr UNIX_SOCK_ADDR_UNNAMED = new UnixSockAddr(new byte[0]); - private Object posixSupport; - private PosixSupportLibrary lib; - private UniversalSockAddrLibrary usaLib; - private AddrInfoCursorLibrary aicLib; + private PosixSupport posixSupport; @Before public void setUp() { posixSupport = withPythonContextRule.getPythonContext().getPosixSupport(); - lib = PosixSupportLibrary.getUncached(); - usaLib = UniversalSockAddrLibrary.getUncached(); - aicLib = AddrInfoCursorLibrary.getUncached(); } @Test @@ -195,21 +188,21 @@ public void fillUniversalSockAddrUnix() throws PosixException { @Test public void dgramUnboundGetsocknameInet4() throws PosixException { int s = createSocket(AF_INET.value, SOCK_DGRAM.value, 0); - checkUsa(new Inet4SockAddr(0, INADDR_ANY.value), lib.getsockname(posixSupport, s)); + checkUsa(new Inet4SockAddr(0, INADDR_ANY.value), posixSupport.getsockname(s)); } @Test public void dgramUnboundGetsocknameInet6() throws PosixException { assumeTrue(isInet6Supported()); int s = createSocket(AF_INET6.value, SOCK_DGRAM.value, 0); - checkUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0), lib.getsockname(posixSupport, s)); + checkUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0), posixSupport.getsockname(s)); } @Test public void dgramUnboundGetsocknameUnix() throws PosixException { assumeTrue("native".equals(backendName)); int s = createSocket(AF_UNIX.value, SOCK_DGRAM.value, 0); - checkUsa(new UnixSockAddr(new byte[0]), lib.getsockname(posixSupport, s)); + checkUsa(new UnixSockAddr(new byte[0]), posixSupport.getsockname(s)); } @Test @@ -430,7 +423,7 @@ public void streamRecvfromInet() throws PosixException { checkUsa(cli.address(), c.getpeername()); c.send(DATA, 0); - assertEquals(AF_UNSPEC.value, usaLib.getFamily(cli.recvfrom(DATA, 0))); + assertEquals(AF_UNSPEC.value, cli.recvfrom(DATA, 0).getFamily()); } @Test @@ -479,7 +472,7 @@ public void streamWriteReadUnix() throws PosixException, IOException { Socket cli = new Socket(AF_UNIX.value, SOCK_STREAM.value); UniversalSockAddr addr = null; try { - addr = lib.createUniversalSockAddrUnix(posixSupport, unixSockAddr); + addr = posixSupport.createUniversalSockAddrUnix(unixSockAddr); } catch (InvalidUnixSocketPathException e) { assumeNoException(e); } @@ -506,7 +499,7 @@ public void dgramUnconnectedGetpeername() { @Test public void dgramListen() { - expectErrno(() -> lib.listen(posixSupport, new UdpServer(AF_INET.value).fd, 5), + expectErrno(() -> posixSupport.listen(new UdpServer(AF_INET.value).fd, 5), OSErrorEnum.EOPNOTSUPP, OSErrorEnum.EACCES /* Some CI machines seem to block this with EACCESS */); } @@ -528,7 +521,7 @@ public void streamUnconnectedGetpeername() { @Test public void streamUnconnectedRead() { expectErrno(() -> { - lib.read(posixSupport, new TcpClient(AF_INET.value).fd, 10); + posixSupport.read(new TcpClient(AF_INET.value).fd, 10); }, OSErrorEnum.ENOTCONN); } @@ -536,7 +529,7 @@ public void streamUnconnectedRead() { public void streamUnconnectedWrite() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.write(posixSupport, new TcpClient(AF_INET.value).fd, Buffer.wrap(DATA)); + posixSupport.write(new TcpClient(AF_INET.value).fd, Buffer.wrap(DATA)); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @@ -550,7 +543,7 @@ public void streamListeningGetpeername() { @Test public void streamListeningRecv() { expectErrno(() -> { - lib.recv(posixSupport, new TcpServer(AF_INET.value).fd, new byte[10], 0, 10, 0); + posixSupport.recv(new TcpServer(AF_INET.value).fd, new byte[10], 0, 10, 0); }, OSErrorEnum.ENOTCONN); } @@ -558,14 +551,14 @@ public void streamListeningRecv() { public void streamListeningSend() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.send(posixSupport, new TcpServer(AF_INET.value).fd, DATA, 0, DATA.length, 0); + posixSupport.send(new TcpServer(AF_INET.value).fd, DATA, 0, DATA.length, 0); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @Test public void streamListeningRead() { expectErrno(() -> { - lib.read(posixSupport, new TcpServer(AF_INET.value).fd, 10); + posixSupport.read(new TcpServer(AF_INET.value).fd, 10); }, OSErrorEnum.ENOTCONN); } @@ -573,7 +566,7 @@ public void streamListeningRead() { public void streamListeningWrite() { // From send(2): Linux may return EPIPE instead of ENOTCONN. expectErrno(() -> { - lib.write(posixSupport, new TcpServer(AF_INET.value).fd, Buffer.wrap(DATA)); + posixSupport.write(new TcpServer(AF_INET.value).fd, Buffer.wrap(DATA)); }, OSErrorEnum.ENOTCONN, OSErrorEnum.EPIPE); } @@ -594,9 +587,9 @@ public void getSocketOptionsAcceptConn() throws PosixException { assumeTrue("native".equals(backendName)); assumeTrue(runsOnLinux()); // darwin defines but does not support SO_ACCEPTCONN int socket = createSocket(AF_INET.value, SOCK_STREAM.value, 0); - lib.bind(posixSupport, socket, createUsa(new Inet4SockAddr(0, INADDR_LOOPBACK.value))); + posixSupport.bind(socket, createUsa(new Inet4SockAddr(0, INADDR_LOOPBACK.value))); assertEquals(0, getIntSockOpt(socket, SOL_SOCKET.value, SO_ACCEPTCONN.value)); - lib.listen(posixSupport, socket, 5); + posixSupport.listen(socket, 5); assertEquals(1, getIntSockOpt(socket, SOL_SOCKET.value, SO_ACCEPTCONN.value)); } @@ -627,7 +620,7 @@ public void nonBlockingDgramRecv() { UdpClient cli = new UdpClient(AF_INET.value); cli.setBlocking(false); assertFalse(cli.getBlocking()); - lib.recv(posixSupport, cli.fd, new byte[10], 0, 10, 0); + posixSupport.recv(cli.fd, new byte[10], 0, 10, 0); }, OSErrorEnum.EWOULDBLOCK); } @@ -637,7 +630,7 @@ public void nonBlockingAccept() throws PosixException { TcpClient cli = new TcpClient(AF_INET.value); srv.setBlocking(false); try { - lib.accept(posixSupport, srv.fd); + posixSupport.accept(srv.fd); fail("Expected accept() to fail with EWOULDBLOCK"); } catch (PosixException e) { assertTrue(e.hasErrno(OSErrorEnum.EWOULDBLOCK)); @@ -646,7 +639,7 @@ public void nonBlockingAccept() throws PosixException { // A completed connect does not guarantee that the connection is already visible to a // non-blocking accept(). Wait until the listening socket reports that it is readable. - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(1, 0)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(1, 0)); assertTrue(res.getReadFds()[0]); srv.accept(cli.address()); } @@ -656,12 +649,12 @@ public void dgramSelect() throws PosixException { UdpServer srv = new UdpServer(AF_INET.value); UdpClient cli = new UdpClient(AF_INET.value); - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); cli.sendto(DATA, 0, srv.usa()); - res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertTrue(res.getReadFds()[0]); checkUsa(cli.address(), srv.recvfrom(DATA, 0)); @@ -676,12 +669,12 @@ public void streamSelect() throws PosixException { TcpServer srv = new TcpServer(AF_INET.value); TcpClient cli = new TcpClient(AF_INET.value); - SelectResult res = lib.select(posixSupport, new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); + SelectResult res = posixSupport.select(new int[]{srv.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); cli.connect(srv.usa()); - res = lib.select(posixSupport, new int[]{srv.fd, cli.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd, cli.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertTrue(res.getReadFds()[0]); assertFalse(res.getReadFds()[1]); @@ -694,7 +687,7 @@ public void streamSelect() throws PosixException { c.send(DATA, 0); - res = lib.select(posixSupport, new int[]{srv.fd, cli.fd, c.fd}, new int[0], new int[0], new Timeval(0, 100000)); + res = posixSupport.select(new int[]{srv.fd, cli.fd, c.fd}, new int[0], new int[0], new Timeval(0, 100000)); assertFalse(res.getReadFds()[0]); // c is readable immediately after shutdown(SHUT_RD), while the data sent to cli may arrive @@ -703,63 +696,63 @@ public void streamSelect() throws PosixException { boolean cliReadable = res.getReadFds()[1]; boolean cReadable = res.getReadFds()[2]; if (!cliReadable) { - SelectResult cliRes = lib.select(posixSupport, new int[]{cli.fd}, new int[0], new int[0], + SelectResult cliRes = posixSupport.select(new int[]{cli.fd}, new int[0], new int[0], new Timeval(1, 0)); cliReadable = cliRes.getReadFds()[0]; } if (!cReadable) { - SelectResult cRes = lib.select(posixSupport, new int[]{c.fd}, new int[0], new int[0], new Timeval(1, 0)); + SelectResult cRes = posixSupport.select(new int[]{c.fd}, new int[0], new int[0], new Timeval(1, 0)); cReadable = cRes.getReadFds()[0]; } assertTrue(cliReadable); assertTrue(cReadable); - assertEquals(0, lib.recv(posixSupport, c.fd, new byte[10], 0, 10, 0)); + assertEquals(0, posixSupport.recv(c.fd, new byte[10], 0, 10, 0)); cli.recv(DATA, 0); } @Test public void getnameinfo() throws PosixException, GetAddrInfoException { - Object[] res = lib.getnameinfo(posixSupport, createUsa(new Inet6SockAddr(443, IN6ADDR_LOOPBACK, 0, 0)), NI_NUMERICSERV.value | NI_NUMERICHOST.value); + Object[] res = posixSupport.getnameinfo(createUsa(new Inet6SockAddr(443, IN6ADDR_LOOPBACK, 0, 0)), NI_NUMERICSERV.value | NI_NUMERICHOST.value); assertThat(p2s(res[0]), anyOf(equalTo("::1"), equalTo("0:0:0:0:0:0:0:1%0"))); assertEquals("443", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), 0); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), 0); assertEquals("localhost", p2s(res[0])); assertEquals("https", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(53535, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(53535, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); assertEquals("53535", p2s(res[1])); } @Test public void getnameinfoUdp() throws PosixException, GetAddrInfoException { assumeTrue(runsOnLinux()); - Object[] res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); + Object[] res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value); assertEquals("exec", p2s(res[1])); - res = lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_DGRAM.value); + res = posixSupport.getnameinfo(createUsa(new Inet4SockAddr(512, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_DGRAM.value); assertThat(p2s(res[1]), anyOf(equalTo("biff"), equalTo("comsat"))); } @Test public void getnameinfoErr() { expectGetAddrInfoException(() -> { - lib.getnameinfo(posixSupport, createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_NAMEREQD.value); + posixSupport.getnameinfo(createUsa(new Inet4SockAddr(443, INADDR_LOOPBACK.value)), NI_NUMERICHOST.value | NI_NAMEREQD.value); }, EAI_NONAME); } @Test public void getaddrinfoErrNoInput() { expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, null, AF_UNSPEC.value, 0, 0, 0); + posixSupport.getaddrinfo(null, null, AF_UNSPEC.value, 0, 0, 0); }, EAI_NONAME); } @Test public void getaddrinfoErrFamily() { expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("http"), -42, 0, 0, 0); + posixSupport.getaddrinfo(null, s2p("http"), -42, 0, 0, 0); }, EAI_FAMILY); } @@ -767,7 +760,7 @@ public void getaddrinfoErrFamily() { public void getaddrinfoErrSockType() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("http"), AF_UNSPEC.value, -42, 0, 0); + posixSupport.getaddrinfo(null, s2p("http"), AF_UNSPEC.value, -42, 0, 0); }, EAI_SOCKTYPE); } @@ -775,7 +768,7 @@ public void getaddrinfoErrSockType() { public void getaddrinfoErrService() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("invalid service"), AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); + posixSupport.getaddrinfo(null, s2p("invalid service"), AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); }, EAI_SERVICE); } @@ -783,7 +776,7 @@ public void getaddrinfoErrService() { public void getaddrinfoErrAddrFamily() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, s2p("::1"), null, AF_INET.value, 0, 0, 0); + posixSupport.getaddrinfo(s2p("::1"), null, AF_INET.value, 0, 0, 0); }, EAI_ADDRFAMILY); } @@ -791,43 +784,43 @@ public void getaddrinfoErrAddrFamily() { public void getaddrinfoBadFlags() { assumeTrue(runsOnLinux()); expectGetAddrInfoException(() -> { - lib.getaddrinfo(posixSupport, null, s2p("https"), AF_INET.value, 0, 0, AI_CANONNAME.value); + posixSupport.getaddrinfo(null, s2p("https"), AF_INET.value, 0, 0, AI_CANONNAME.value); }, EAI_BADFLAGS); } @Test public void getaddrinfoServiceOnly() throws PosixException, GetAddrInfoException { Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, null, service, AF_UNSPEC.value, SOCK_STREAM.value, 0, 0); - cleanup.add(() -> aicLib.release(aic)); + AddrInfoCursor aic = posixSupport.getaddrinfo(null, service, AF_UNSPEC.value, SOCK_STREAM.value, 0, 0); + cleanup.add(() -> aic.release()); do { - int family = aicLib.getFamily(aic); + int family = aic.getFamily(); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertNull(aicLib.getCanonName(aic)); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertNull(aic.getCanonName()); - UniversalSockAddr usa = aicLib.getSockAddr(aic); - assertEquals(family, usaLib.getFamily(usa)); + UniversalSockAddr usa = aic.getSockAddr(); + assertEquals(family, usa.getFamily()); if (family == AF_INET.value) { - Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); + Inet4SockAddr addr2 = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); assertEquals(443, addr2.getPort()); } - } while (aicLib.next(aic)); + } while (aic.next()); } @Test public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, null, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_PASSIVE.value); - cleanup.add(() -> aicLib.release(aic)); - assertEquals(AF_INET.value, aicLib.getFamily(aic)); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_TCP.value, aicLib.getProtocol(aic)); - assertNull(aicLib.getCanonName(aic)); - - UniversalSockAddr usa = aicLib.getSockAddr(aic); - Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); + AddrInfoCursor aic = posixSupport.getaddrinfo(null, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_PASSIVE.value); + cleanup.add(aic::release); + assertEquals(AF_INET.value, aic.getFamily()); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertEquals(IPPROTO_TCP.value, aic.getProtocol()); + assertNull(aic.getCanonName()); + + UniversalSockAddr usa = aic.getSockAddr(); + Inet4SockAddr addr = usa.asInet4SockAddr(); assertEquals(INADDR_ANY.value, addr.getAddress()); assertEquals(443, addr.getPort()); } @@ -835,37 +828,37 @@ public void getaddrinfoPassive() throws PosixException, GetAddrInfoException { @Test public void getaddrinfoServerOnlyNoCanon() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, node, null, AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); - cleanup.add(() -> aicLib.release(aic)); + AddrInfoCursor aic = posixSupport.getaddrinfo(node, null, AF_UNSPEC.value, SOCK_DGRAM.value, 0, 0); + cleanup.add(aic::release); do { - assertEquals(SOCK_DGRAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_UDP.value, aicLib.getProtocol(aic)); - assertNull(aicLib.getCanonName(aic)); - - if (aicLib.getFamily(aic) == AF_INET.value) { - UniversalSockAddr usa = aicLib.getSockAddr(aic); - assertEquals(AF_INET.value, usaLib.getFamily(usa)); - Inet4SockAddr addr = usaLib.asInet4SockAddr(usa); + assertEquals(SOCK_DGRAM.value, aic.getSockType()); + assertEquals(IPPROTO_UDP.value, aic.getProtocol()); + assertNull(aic.getCanonName()); + + if (aic.getFamily() == AF_INET.value) { + UniversalSockAddr usa = aic.getSockAddr(); + assertEquals(AF_INET.value, usa.getFamily()); + Inet4SockAddr addr = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr.getAddress()); assertEquals(0, addr.getPort()); } - } while (aicLib.next(aic)); + } while (aic.next()); } @Test public void getaddrinfo() throws PosixException, GetAddrInfoException { Object node = s2p("localhost"); Object service = s2p("https"); - AddrInfoCursor aic = lib.getaddrinfo(posixSupport, node, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_CANONNAME.value); - cleanup.add(() -> aicLib.release(aic)); - assertEquals(AF_INET.value, aicLib.getFamily(aic)); - assertEquals(SOCK_STREAM.value, aicLib.getSockType(aic)); - assertEquals(IPPROTO_TCP.value, aicLib.getProtocol(aic)); - assertEquals("localhost", p2s(aicLib.getCanonName(aic))); - - UniversalSockAddr usa = aicLib.getSockAddr(aic); - assertEquals(AF_INET.value, usaLib.getFamily(usa)); - Inet4SockAddr addr2 = usaLib.asInet4SockAddr(usa); + AddrInfoCursor aic = posixSupport.getaddrinfo(node, service, AF_INET.value, 0, IPPROTO_TCP.value, AI_CANONNAME.value); + cleanup.add(aic::release); + assertEquals(AF_INET.value, aic.getFamily()); + assertEquals(SOCK_STREAM.value, aic.getSockType()); + assertEquals(IPPROTO_TCP.value, aic.getProtocol()); + assertEquals("localhost", p2s(aic.getCanonName())); + + UniversalSockAddr usa = aic.getSockAddr(); + assertEquals(AF_INET.value, usa.getFamily()); + Inet4SockAddr addr2 = usa.asInet4SockAddr(); assertEquals(INADDR_LOOPBACK.value, addr2.getAddress()); assertEquals(443, addr2.getPort()); } @@ -916,7 +909,7 @@ public void inet_addr() { for (Map.Entry a : ip4Addresses.entrySet()) { String src = a.getKey(); Integer expected = a.getValue(); - int actual = lib.inet_addr(posixSupport, s2p(src)); + int actual = posixSupport.inet_addr(s2p(src)); assertEquals("inet_addr(\"" + src + "\")", expected == null ? INADDR_NONE.value : expected, actual); } } @@ -928,7 +921,7 @@ public void inet_aton() { Integer expected = a.getValue(); Integer actual; try { - actual = lib.inet_aton(posixSupport, s2p(src)); + actual = posixSupport.inet_aton(s2p(src)); } catch (InvalidAddressException e) { actual = null; } @@ -938,36 +931,36 @@ public void inet_aton() { @Test public void inet_ntoa() { - assertEquals("0.0.0.0", p2s(lib.inet_ntoa(posixSupport, 0x00000000))); - assertEquals("1.2.3.4", p2s(lib.inet_ntoa(posixSupport, 0x01020304))); - assertEquals("18.52.86.120", p2s(lib.inet_ntoa(posixSupport, 0x12345678))); - assertEquals("255.255.255.255", p2s(lib.inet_ntoa(posixSupport, 0xffffffff))); + assertEquals("0.0.0.0", p2s(posixSupport.inet_ntoa(0x00000000))); + assertEquals("1.2.3.4", p2s(posixSupport.inet_ntoa(0x01020304))); + assertEquals("18.52.86.120", p2s(posixSupport.inet_ntoa(0x12345678))); + assertEquals("255.255.255.255", p2s(posixSupport.inet_ntoa(0xffffffff))); } @Test public void inet_pton() throws PosixException, InvalidAddressException { - assertArrayEquals(new byte[]{1, 2, -2, -1}, lib.inet_pton(posixSupport, AF_INET.value, s2p("1.2.254.255"))); - assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, lib.inet_pton(posixSupport, AF_INET6.value, s2p("1::FF"))); - assertArrayEquals(MAPPED_LOOPBACK, lib.inet_pton(posixSupport, AF_INET6.value, s2p("::ffff:127.0.0.1"))); + assertArrayEquals(new byte[]{1, 2, -2, -1}, posixSupport.inet_pton(AF_INET.value, s2p("1.2.254.255"))); + assertArrayEquals(new byte[]{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, posixSupport.inet_pton(AF_INET6.value, s2p("1::FF"))); + assertArrayEquals(MAPPED_LOOPBACK, posixSupport.inet_pton(AF_INET6.value, s2p("::ffff:127.0.0.1"))); } @Test public void inet_pton_eafnosupport() { expectErrno(() -> { - lib.inet_pton(posixSupport, AF_UNSPEC.value, s2p("")); + posixSupport.inet_pton(AF_UNSPEC.value, s2p("")); }, OSErrorEnum.EAFNOSUPPORT); } @Test public void inet_pton_invalid_inet6() { Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET6.value, s2p(":"))); + () -> posixSupport.inet_pton(AF_INET6.value, s2p(":"))); } @Test public void inet_pton_invalid_inet4_as_inet6() { Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET6.value, s2p("127.0.0.1"))); + () -> posixSupport.inet_pton(AF_INET6.value, s2p("127.0.0.1"))); } @Test @@ -980,7 +973,7 @@ public void inet_pton_invalid_inet4() throws PosixException { }; for (String src : addresses) { try { - lib.inet_pton(posixSupport, AF_INET.value, s2p(src)); + posixSupport.inet_pton(AF_INET.value, s2p(src)); fail("inet_pton(AF_INET, \"" + src + "\") was expected to fail"); } catch (InvalidAddressException e) { // expected @@ -993,33 +986,33 @@ public void inet_pton_inet4_octal() { // native inet_pton on darwin accepts leading zeroes (but handles them as decimal) assumeTrue("java".equals(backendName) || runsOnLinux()); Assert.assertThrows(InvalidAddressException.class, - () -> lib.inet_pton(posixSupport, AF_INET.value, s2p("1.2.010.4"))); + () -> posixSupport.inet_pton(AF_INET.value, s2p("1.2.010.4"))); } @Test public void inet_ntop() throws PosixException { - assertEquals("1.0.255.254", p2s(lib.inet_ntop(posixSupport, AF_INET.value, new byte[]{1, 0, -1, -2, -3}))); - assertThat(p2s(lib.inet_ntop(posixSupport, AF_INET6.value, new byte[]{-3, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4})), + assertEquals("1.0.255.254", p2s(posixSupport.inet_ntop(AF_INET.value, new byte[]{1, 0, -1, -2, -3}))); + assertThat(p2s(posixSupport.inet_ntop(AF_INET6.value, new byte[]{-3, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4})), anyOf(equalTo("fdfe:0:ff00::1:203"), equalTo("fdfe:0:ff00:0:0:0:1:203"))); - assertEquals("::ffff:127.0.0.1", p2s(lib.inet_ntop(posixSupport, AF_INET6.value, MAPPED_LOOPBACK))); + assertEquals("::ffff:127.0.0.1", p2s(posixSupport.inet_ntop(AF_INET6.value, MAPPED_LOOPBACK))); } @Test public void inet_ntop_eafnosupport() { expectErrno(() -> { - lib.inet_ntop(posixSupport, AF_UNSPEC.value, new byte[16]); + posixSupport.inet_ntop(AF_UNSPEC.value, new byte[16]); }, OSErrorEnum.EAFNOSUPPORT); } @Test public void inet_ntop_len() { Assert.assertThrows(IllegalArgumentException.class, - () -> lib.inet_ntop(posixSupport, AF_INET6.value, new byte[15])); + () -> posixSupport.inet_ntop(AF_INET6.value, new byte[15])); } @Test public void gethostname() throws PosixException { - assertTrue(p2s(lib.gethostname(posixSupport)).length() > 0); + assertFalse(p2s(posixSupport.gethostname()).isEmpty()); } private static FamilySpecificSockAddr localAddress(int family, int port) { @@ -1030,13 +1023,13 @@ private static FamilySpecificSockAddr localAddress(int family, int port) { } } - private int checkBound(int family, UniversalSockAddr usa) { - assertEquals(family, usaLib.getFamily(usa)); + private static int checkBound(int family, UniversalSockAddr usa) { + assertEquals(family, usa.getFamily()); int port; if (family == AF_INET.value) { - port = usaLib.asInet4SockAddr(usa).getPort(); + port = usa.asInet4SockAddr().getPort(); } else if (family == AF_INET6.value) { - port = usaLib.asInet6SockAddr(usa).getPort(); + port = usa.asInet6SockAddr().getPort(); } else { throw CompilerDirectives.shouldNotReachHere(); } @@ -1045,26 +1038,23 @@ private int checkBound(int family, UniversalSockAddr usa) { } private void checkUsa(FamilySpecificSockAddr expectedAddr, UniversalSockAddr actualUsa) { - if (expectedAddr instanceof Inet4SockAddr) { - Inet4SockAddr expected = (Inet4SockAddr) expectedAddr; - assertEquals(AF_INET.value, usaLib.getFamily(actualUsa)); - Inet4SockAddr actual = usaLib.asInet4SockAddr(actualUsa); + if (expectedAddr instanceof Inet4SockAddr expected) { + assertEquals(AF_INET.value, actualUsa.getFamily()); + Inet4SockAddr actual = actualUsa.asInet4SockAddr(); assertEquals(expected.getPort(), actual.getPort()); assertEquals(expected.getAddress(), actual.getAddress()); - } else if (expectedAddr instanceof Inet6SockAddr) { - Inet6SockAddr expected = (Inet6SockAddr) expectedAddr; - assertEquals(AF_INET6.value, usaLib.getFamily(actualUsa)); - Inet6SockAddr actual = usaLib.asInet6SockAddr(actualUsa); + } else if (expectedAddr instanceof Inet6SockAddr expected) { + assertEquals(AF_INET6.value, actualUsa.getFamily()); + Inet6SockAddr actual = actualUsa.asInet6SockAddr(); assertEquals(expected.getPort(), actual.getPort()); assertArrayEquals(expected.getAddress(), actual.getAddress()); assertEquals(expected.getScopeId(), actual.getScopeId()); if ("native".equals(backendName)) { assertEquals(expected.getFlowInfo(), actual.getFlowInfo()); } - } else if (expectedAddr instanceof UnixSockAddr) { - UnixSockAddr expected = (UnixSockAddr) expectedAddr; - assertEquals(AF_UNIX.value, usaLib.getFamily(actualUsa)); - UnixSockAddr actual = usaLib.asUnixSockAddr(actualUsa); + } else if (expectedAddr instanceof UnixSockAddr expected) { + assertEquals(AF_UNIX.value, actualUsa.getFamily()); + UnixSockAddr actual = actualUsa.asUnixSockAddr(); assertNullTerminatedArrayEquals(expected.getPath(), actual.getPath()); } else { fail("Unexpected subclass of FamilySpecificSockAddr: " + expectedAddr.getClass().getName()); @@ -1080,11 +1070,11 @@ private byte[] getNulTerminatedTempFileName() throws IOException { } private Object s2p(String s) { - return lib.createCStringFromString(posixSupport, toTruffleStringUncached(s)); + return PosixSupportNodes.CreateCStringFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(s)); } private String p2s(Object p) { - return lib.getCStringAsString(posixSupport, p).toJavaStringUncached(); + return PosixSupportNodes.GetCStringAsStringNode.executeUncached(posixSupport, p).toJavaStringUncached(); } private static void expectErrno(ThrowingRunnable runnable, OSErrorEnum... expectedErrorCodes) { @@ -1103,19 +1093,19 @@ private static void expectGetAddrInfoException(ThrowingRunnable runnable, Mandat } private int createSocket(int family, int type, int protocol) throws PosixException { - int sockfd = lib.socket(posixSupport, family, type, protocol); - cleanup.add(() -> lib.close(posixSupport, sockfd)); + int sockfd = posixSupport.socket(family, type, protocol); + cleanup.add(() -> posixSupport.close(sockfd)); return sockfd; } private UniversalSockAddr createUsa(FamilySpecificSockAddr src) throws PosixException { if (src instanceof Inet4SockAddr inet4SockAddr) { - return lib.createUniversalSockAddrInet4(posixSupport, inet4SockAddr); + return posixSupport.createUniversalSockAddrInet4(inet4SockAddr); } else if (src instanceof Inet6SockAddr inet6SockAddr) { - return lib.createUniversalSockAddrInet6(posixSupport, inet6SockAddr); + return posixSupport.createUniversalSockAddrInet6(inet6SockAddr); } else if (src instanceof UnixSockAddr unixSockAddr) { try { - return lib.createUniversalSockAddrUnix(posixSupport, unixSockAddr); + return posixSupport.createUniversalSockAddrUnix(unixSockAddr); } catch (InvalidUnixSocketPathException e) { assumeNoException(e); return null; // unreachable @@ -1127,14 +1117,14 @@ private UniversalSockAddr createUsa(FamilySpecificSockAddr src) throws PosixExce private int getIntSockOpt(int socket, int level, int option) throws PosixException { byte[] buf = new byte[4]; - assertEquals(4, lib.getsockopt(posixSupport, socket, level, option, buf, 4)); + assertEquals(4, posixSupport.getsockopt(socket, level, option, buf, 4)); return nativeByteArraySupport().getInt(buf, 0); } private void setIntSockOpt(int socket, int level, int option, int value) throws PosixException { byte[] buf = new byte[4]; nativeByteArraySupport().putInt(buf, 0, value); - lib.setsockopt(posixSupport, socket, level, option, buf, 4); + posixSupport.setsockopt(socket, level, option, buf, 4); } private static ByteArraySupport nativeByteArraySupport() { @@ -1182,77 +1172,77 @@ private class Socket { } void bind(FamilySpecificSockAddr sockAddr) throws PosixException { - lib.bind(posixSupport, fd, createUsa(sockAddr)); + posixSupport.bind(fd, createUsa(sockAddr)); } void bindAny() throws PosixException { if (family == AF_INET.value) { - lib.bind(posixSupport, fd, createUsa(new Inet4SockAddr(0, INADDR_ANY.value))); + posixSupport.bind(fd, createUsa(new Inet4SockAddr(0, INADDR_ANY.value))); } else if (family == AF_INET6.value) { - lib.bind(posixSupport, fd, createUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0))); + posixSupport.bind(fd, createUsa(new Inet6SockAddr(0, IN6ADDR_ANY, 0, 0))); } else { throw CompilerDirectives.shouldNotReachHere(); } } void connect(UniversalSockAddr addr) throws PosixException { - lib.connect(posixSupport, fd, addr); + posixSupport.connect(fd, addr); } void listen(int backlog) throws PosixException { - lib.listen(posixSupport, fd, backlog); + posixSupport.listen(fd, backlog); } UniversalSockAddr getpeername() throws PosixException { - return lib.getpeername(posixSupport, fd); + return posixSupport.getpeername(fd); } UniversalSockAddr getsockname() throws PosixException { - return lib.getsockname(posixSupport, fd); + return posixSupport.getsockname(fd); } void recv(byte[] expectedData, int flags) throws PosixException { byte[] buf = new byte[expectedData.length * 2]; - assertEquals(expectedData.length, lib.recv(posixSupport, fd, buf, 0, buf.length, flags)); + assertEquals(expectedData.length, posixSupport.recv(fd, buf, 0, buf.length, flags)); assertArrayEquals(expectedData, Arrays.copyOf(buf, expectedData.length)); } UniversalSockAddr recvfrom(byte[] expectedData, int flags) throws PosixException { byte[] buf = new byte[expectedData.length * 2]; - RecvfromResult recvfromResult = lib.recvfrom(posixSupport, fd, buf, 0, buf.length, flags); + RecvfromResult recvfromResult = posixSupport.recvfrom(fd, buf, 0, buf.length, flags); assertEquals(expectedData.length, recvfromResult.readBytes); assertArrayEquals(expectedData, Arrays.copyOf(buf, expectedData.length)); return recvfromResult.sockAddr; } void send(byte[] data, int flags) throws PosixException { - assertEquals(data.length, lib.send(posixSupport, fd, data, 0, data.length, flags)); + assertEquals(data.length, posixSupport.send(fd, data, 0, data.length, flags)); } void sendto(byte[] data, int flags, UniversalSockAddr destAddr) throws PosixException { - assertEquals(data.length, lib.sendto(posixSupport, fd, data, 0, data.length, flags, destAddr)); + assertEquals(data.length, posixSupport.sendto(fd, data, 0, data.length, flags, destAddr)); } void write(byte[] data) throws PosixException { - assertEquals(data.length, lib.write(posixSupport, fd, Buffer.wrap(data))); + assertEquals(data.length, posixSupport.write(fd, Buffer.wrap(data))); } void read(byte[] expectedData) throws PosixException { - Buffer buf = lib.read(posixSupport, fd, expectedData.length * 2); + Buffer buf = posixSupport.read(fd, expectedData.length * 2L); assertEquals(expectedData.length, buf.length); assertArrayEquals(expectedData, Arrays.copyOf(buf.data, expectedData.length)); } void shutdown(int how) throws PosixException { - lib.shutdown(posixSupport, fd, how); + posixSupport.shutdown(fd, how); } void setBlocking(boolean block) throws PosixException { - lib.setBlocking(posixSupport, fd, block); + posixSupport.setBlocking(fd, block); } boolean getBlocking() throws PosixException { - return lib.getBlocking(posixSupport, fd); + return posixSupport.getBlocking(fd); } FamilySpecificSockAddr address() throws PosixException { @@ -1276,8 +1266,8 @@ private class Server extends Socket { } int acceptFd(FamilySpecificSockAddr expectedAddress) throws PosixException { - AcceptResult acceptResult = lib.accept(posixSupport, fd); - cleanup.add(() -> lib.close(posixSupport, acceptResult.socketFd)); + AcceptResult acceptResult = posixSupport.accept(fd); + cleanup.add(() -> posixSupport.close(acceptResult.socketFd)); checkUsa(expectedAddress, acceptResult.sockAddr); return acceptResult.socketFd; } @@ -1292,7 +1282,7 @@ private class InetServer extends Server { if (type == SOCK_STREAM.value) { listen(5); } - UniversalSockAddr boundUsa = lib.getsockname(posixSupport, fd); + UniversalSockAddr boundUsa = posixSupport.getsockname(fd); port = checkBound(family, boundUsa); } } diff --git a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java index a71acd9aad..a94b8c4eac 100644 --- a/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java +++ b/graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/PathConversionNodeTests.java @@ -67,8 +67,9 @@ import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.tuple.PTuple; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.test.PythonTests; import com.oracle.graal.python.util.Function; @@ -91,9 +92,8 @@ public static String[] params() { public void setUp() { org.junit.Assume.assumeTrue(backendName.equals("java") || !IS_WINDOWS); PythonTests.enterContext(Collections.singletonMap("python.PosixModuleBackend", backendName), new String[0]); - Object posixSupport = PythonContext.get(null).getPosixSupport(); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - pathToString = p -> posixLib.getPathAsString(posixSupport, p.value).toJavaStringUncached(); + PosixSupport posixSupport = PythonContext.get(null).getPosixSupport(); + pathToString = p -> PosixSupportNodes.GetPathAsStringNode.executeUncached(posixSupport, p.value).toJavaStringUncached(); } @After diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py index eedd1c10cd..26829283a7 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py @@ -147,6 +147,65 @@ class TypeWithAttrInDict: NativeTypeWithAttr.attr = "str" +class VectorcallMethodReceiver: + def combine(self, positional, *, keyword="default"): + return type(self).__name__, positional, keyword + + +NativeTypeWithAttr.combine = VectorcallMethodReceiver.combine + + +NativeVectorcallMethodReceiver = CPyExtHeapType( + "NativeVectorcallMethodReceiver", + code=''' + static PyObject* native_combine(PyObject* self, PyObject* const* args, + Py_ssize_t nargs, PyObject* kwnames) { + PyObject* positional = PyTuple_New(nargs); + if (positional == NULL) { + return NULL; + } + for (Py_ssize_t i = 0; i < nargs; i++) { + PyTuple_SET_ITEM(positional, i, Py_NewRef(args[i])); + } + PyObject* keywords = PyDict_New(); + if (keywords == NULL) { + Py_DECREF(positional); + return NULL; + } + if (kwnames != NULL) { + Py_ssize_t nkw = PyTuple_GET_SIZE(kwnames); + for (Py_ssize_t i = 0; i < nkw; i++) { + if (PyDict_SetItem(keywords, PyTuple_GET_ITEM(kwnames, i), args[nargs + i]) < 0) { + Py_DECREF(positional); + Py_DECREF(keywords); + return NULL; + } + } + } + PyObject* result = PyTuple_Pack(2, positional, keywords); + Py_DECREF(positional); + Py_DECREF(keywords); + return result; + } + + static PyMethodDef native_methods[] = { + {"combine", (PyCFunction)(void(*)(void))native_combine, METH_FASTCALL | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} + }; + ''', + slots=['{Py_tp_methods, native_methods}'], +) + + +class NativeVectorcallMethodSubclass(NativeVectorcallMethodReceiver): + pass + + +native_vectorcall_method_shadowed = NativeVectorcallMethodSubclass() +native_vectorcall_method_shadowed.combine = lambda positional, *, keyword="default": ( + "shadowed", positional, keyword) + + class DelAttrObject: def __init__(self): self.a = 1 @@ -401,6 +460,43 @@ def __hash__(self): argspec="Oss", callfunction="PyObject_CallMethod" ) + test_PyObject_VectorcallMethod = CPyExtFunction( + lambda args: getattr(args[0], args[1])( + args[2], **({} if args[3] is None else {"keyword": args[3]})), + lambda: ( + (VectorcallMethodReceiver(), "combine", "managed-positional", "managed-keyword"), + (VectorcallMethodReceiver(), "combine", "managed-positional", None), + (NativeTypeWithAttr(), "combine", "native-positional", "native-keyword"), + (NativeTypeWithAttr(), "combine", "native-positional", None), + (NativeVectorcallMethodReceiver(), "combine", "native-method-positional", "native-method-keyword"), + (NativeVectorcallMethodReceiver(), "combine", "native-method-positional", None), + (native_vectorcall_method_shadowed, "combine", "shadowed-positional", "shadowed-keyword"), + ), + code=''' + static PyObject* wrap_PyObject_VectorcallMethod(PyObject* receiver, PyObject* name, + PyObject* positional, PyObject* keyword_value) { + PyObject* args[3] = {receiver, positional, keyword_value}; + PyObject* keyword_names = NULL; + if (keyword_value != Py_None) { + PyObject* keyword_name = PyUnicode_FromString("keyword"); + if (keyword_name == NULL) { + return NULL; + } + keyword_names = PyTuple_Pack(1, keyword_name); + Py_DECREF(keyword_name); + if (keyword_names == NULL) { + return NULL; + } + } + PyObject* result = PyObject_VectorcallMethod(name, args, 2, keyword_names); + Py_XDECREF(keyword_names); + return result; + } + ''', + arguments=["PyObject* receiver", "PyObject* name", "PyObject* positional", "PyObject* keyword_value"], + argspec="OOOO", + callfunction="wrap_PyObject_VectorcallMethod", + ) test_PyObject_Type = CPyExtFunction( type, lambda: ( diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py index 8f05308339..43240045a9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py @@ -92,6 +92,135 @@ def __getattribute__(self, key): class TestObject(unittest.TestCase): + def test_get_method_keeps_method_descriptors_unbound(self): + module = compile_module_from_string( + """ + #include + + PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *, PyObject *, PyObject **); + + static PyObject* native_descriptor_call(PyObject* self, PyObject* args, PyObject* kwargs) { + if (PyTuple_GET_SIZE(args) != 1 || (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0)) { + PyErr_SetString(PyExc_TypeError, "expected exactly one positional argument"); + return NULL; + } + return Py_NewRef(PyTuple_GET_ITEM(args, 0)); + } + + static PyObject* native_descriptor_get(PyObject* self, PyObject* obj, PyObject* type) { + if (obj == NULL || obj == Py_None) { + return Py_NewRef(self); + } + return PyMethod_New(self, obj); + } + + static PyTypeObject NativeMethodDescriptor_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "test_get_method.NativeMethodDescriptor", + .tp_basicsize = sizeof(PyObject), + .tp_call = native_descriptor_call, + .tp_descr_get = native_descriptor_get, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_METHOD_DESCRIPTOR, + }; + + static PyObject* get_method(PyObject* self, PyObject* args) { + PyObject* obj; + PyObject* name; + if (!PyArg_ParseTuple(args, "OO:get_method", &obj, &name)) { + return NULL; + } + PyObject* method = NULL; + int is_method = _PyObject_GetMethod(obj, name, &method); + if (method == NULL) { + return NULL; + } + PyObject* result = PyTuple_New(2); + if (result == NULL) { + Py_DECREF(method); + return NULL; + } + PyTuple_SET_ITEM(result, 0, PyBool_FromLong(is_method)); + PyTuple_SET_ITEM(result, 1, method); + return result; + } + + static PyMethodDef methods[] = { + {"get_method", get_method, METH_VARARGS, NULL}, + {NULL, NULL, 0, NULL} + }; + + static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, "test_get_method", NULL, -1, methods + }; + + PyMODINIT_FUNC PyInit_test_get_method(void) { + if (PyType_Ready(&NativeMethodDescriptor_Type) < 0) { + return NULL; + } + PyObject* m = PyModule_Create(&module); + if (m == NULL) { + return NULL; + } + PyObject* descriptor = NativeMethodDescriptor_Type.tp_alloc(&NativeMethodDescriptor_Type, 0); + if (descriptor == NULL || PyModule_AddObject(m, "native_method_descriptor", descriptor) < 0) { + Py_XDECREF(descriptor); + Py_DECREF(m); + return NULL; + } + return m; + } + """, + "test_get_method", + ) + + class C: + def method(self): + return self + + obj = C() + is_method, method = module.get_method(obj, "method") + assert is_method is True + assert method(obj) is obj + + Native = CPyExtType( + "GetMethodNative", + """ + static PyObject* get_self(PyObject* self, PyObject* unused) { + return Py_NewRef(self); + } + """, + tp_methods='{"get_self", (PyCFunction)get_self, METH_NOARGS, ""}', + ) + native_obj = Native() + is_method, method = module.get_method(native_obj, "get_self") + assert is_method is True + assert method(native_obj) is native_obj + + class WithNativeMethodDescriptor: + native_method_descriptor = module.native_method_descriptor + + native_descriptor_obj = WithNativeMethodDescriptor() + is_method, method = module.get_method(native_descriptor_obj, "native_method_descriptor") + assert is_method is True + assert method is module.native_method_descriptor + assert method(native_descriptor_obj) is native_descriptor_obj + assert native_descriptor_obj.native_method_descriptor() is native_descriptor_obj + + obj.method = lambda: "instance attribute" + is_method, method = module.get_method(obj, "method") + assert is_method is False + assert method() == "instance attribute" + + class WithGetAttribute: + def __getattribute__(self, name): + if name == "method": + return lambda: "custom getattribute" + return object.__getattribute__(self, name) + + is_method, method = module.get_method(WithGetAttribute(), "method") + assert is_method is False + assert method() == "custom getattribute" + def test_iter_dict_before_getattr_property(self): module = compile_module_from_string( """ diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py index 2b6132af44..da45148006 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py @@ -1670,6 +1670,57 @@ def __call__(self, *args, **kwargs): assert obj.__call__({'b': 2}, a=1) == {'a': 1, 'b': 2} +def test_native_vectorcall(): + NativeVectorcall = CPyExtType( + name='NativeVectorcall', + cmembers='vectorcallfunc vectorcall;', + code=r''' + static PyObject* native_vectorcall(PyObject* self, PyObject* const* args, size_t nargsf, PyObject* kwnames) { + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + Py_ssize_t nkwargs = kwnames ? PyTuple_GET_SIZE(kwnames) : 0; + PyObject* positional = PyTuple_New(nargs); + PyObject* keywords = PyDict_New(); + if (!positional || !keywords) { + Py_XDECREF(positional); + Py_XDECREF(keywords); + return NULL; + } + for (Py_ssize_t i = 0; i < nargs; i++) { + Py_INCREF(args[i]); + PyTuple_SET_ITEM(positional, i, args[i]); + } + for (Py_ssize_t i = 0; i < nkwargs; i++) { + if (PyDict_SetItem(keywords, PyTuple_GET_ITEM(kwnames, i), args[nargs + i]) < 0) { + Py_DECREF(positional); + Py_DECREF(keywords); + return NULL; + } + } + return Py_BuildValue("NN", positional, keywords); + } + + static PyObject* native_tp_call(PyObject* self, PyObject* args, PyObject* kwargs) { + return PyUnicode_FromString("tp_call"); + } + + static PyObject* native_vectorcall_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) { + NativeVectorcallObject* self = (NativeVectorcallObject*)type->tp_alloc(type, 0); + if (self) { + self->vectorcall = native_vectorcall; + } + return (PyObject*)self; + } + ''', + tp_flags='Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL', + tp_vectorcall_offset='offsetof(NativeVectorcallObject, vectorcall)', + tp_call='native_tp_call', + tp_new='native_vectorcall_new', + ) + + callable_obj = NativeVectorcall() + assert callable_obj(1, 2, keyword=3) == ((1, 2), {'keyword': 3}) + + def test_richcmp(): MyNativeIntSubType = CPyExtType("MyNativeIntSubTypeForRichCmpTest", ready_code = "MyNativeIntSubTypeForRichCmpTestType.tp_new = PyLong_Type.tp_new;", diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py b/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py index 643e8d2cde..3ef5a5b2eb 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_generators.py @@ -9,6 +9,33 @@ from tests import util +class AsyncGeneratorTest(unittest.TestCase): + def test_aclose_await_in_finally(self): + resumed = [] + + class Suspend: + def __await__(self): + return (yield "suspended") + + async def gen(): + try: + yield 1 + finally: + resumed.append(await Suspend()) + + g = gen() + with self.assertRaises(StopIteration) as cm: + g.__anext__().send(None) + self.assertEqual(cm.exception.value, 1) + + close = g.aclose() + self.assertEqual(close.send(None), "suspended") + self.assertEqual(resumed, []) + with self.assertRaises(StopIteration): + close.send(42) + self.assertEqual(resumed, [42]) + + class ExceptionTest(unittest.TestCase): # Tests for the issue #23353: check that the currently handled exception # is correctly saved/restored in PyEval_EvalFrameEx(). diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py b/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py new file mode 100644 index 0000000000..54cddc373e --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_pwd.py @@ -0,0 +1,180 @@ +# Copyright (c) 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 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import shlex +import shutil +import subprocess +import sys +import tempfile +import textwrap +import unittest + +from tests.util import run_subprocess_with_graalpy_startup_retry + + +POSIX_BACKEND_IS_JAVA = sys.implementation.name == "graalpy" and __graalpython__.posix_module_backend() == "java" + + +@unittest.skipUnless(sys.platform == "linux", "requires Linux LD_PRELOAD") +@unittest.skipIf(POSIX_BACKEND_IS_JAVA, "requires native password database lookups") +class PwdLookupErrorTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + compiler = shlex.split(os.environ.get("CC", "cc")) + if not compiler or shutil.which(compiler[0]) is None: + raise unittest.SkipTest("requires a C compiler") + temporary_directory = tempfile.TemporaryDirectory() + cls.addClassCleanup(temporary_directory.cleanup) + source = os.path.join(temporary_directory.name, "pwd_lookup_error.c") + cls.library = os.path.join(temporary_directory.name, "pwd_lookup_error.so") + # Inject the libc error itself, so the test exercises the real pwd builtin + # and native POSIX backend without touching the host password database. + with open(source, "w") as f: + f.write(textwrap.dedent("""\ + #include + #include + #include + #include + + static int retry_count; + + int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, + size_t buffer_size, struct passwd **result) { + *result = NULL; + if (uid == 2147483646) { + if (retry_count++ == 0) { + return ERANGE; + } + const char data[] = "graalpy_test_user\\0/home/graalpy_test_user\\0/bin/sh"; + if (buffer_size < sizeof(data)) { + return ERANGE; + } + memcpy(buffer, data, sizeof(data)); + pwd->pw_name = buffer; + pwd->pw_dir = buffer + strlen(buffer) + 1; + pwd->pw_shell = pwd->pw_dir + strlen(pwd->pw_dir) + 1; + pwd->pw_uid = uid; + pwd->pw_gid = uid; + pwd->pw_passwd = "x"; + pwd->pw_gecos = ""; + *result = pwd; + return 0; + } + errno = ENOENT; + return ENOENT; + } + + int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, + size_t buffer_size, struct passwd **result) { + *result = NULL; + errno = ENOENT; + return ENOENT; + } + """)) + result = subprocess.run( + [*compiler, "-shared", "-fPIC", source, "-o", cls.library], + capture_output=True, text=True, timeout=60, + ) + if result.returncode: + raise AssertionError(f"Could not compile password lookup shim:\n{result.stdout}\n{result.stderr}") + + def run_child(self, code, *, no_site=True): + env = os.environ.copy() + env.pop("HOME", None) + env.pop("PYTHONUSERBASE", None) + env.pop("PYTHONNOUSERSITE", None) + env["LD_PRELOAD"] = self.library + (" " + env["LD_PRELOAD"] if env.get("LD_PRELOAD") else "") + args = [sys.executable] + if no_site: + args.append("-S") + args.extend(["-c", textwrap.dedent(code)]) + result = run_subprocess_with_graalpy_startup_retry(args, env=env, text=True, timeout=60) + self.assertEqual(result.returncode, 0, f"{result.stdout}\n{result.stderr}") + + def test_getpwuid_lookup_error_is_keyerror(self): + self.run_child("""\ + import os + import pwd + + try: + pwd.getpwuid(os.getuid()) + except KeyError: + pass + else: + raise AssertionError("Expected KeyError for a failed password database lookup") + """) + + def test_getpwuid_retries_erange(self): + self.run_child("""\ + import pwd + + entry = pwd.getpwuid(2147483646) + assert entry.pw_name == "graalpy_test_user", entry + assert entry.pw_dir == "/home/graalpy_test_user", entry + assert entry.pw_shell == "/bin/sh", entry + assert entry.pw_uid == 2147483646, entry + """) + + def test_getpwnam_lookup_error_is_keyerror(self): + self.run_child("""\ + import pwd + + try: + pwd.getpwnam("graalpy_test_user") + except KeyError: + pass + else: + raise AssertionError("Expected KeyError for a failed password database lookup") + """) + + def test_expanduser_with_lookup_error(self): + self.run_child("""\ + import os + + assert os.path.expanduser("~/.local") == "~/.local" + """) + + def test_site_startup_with_lookup_error(self): + # No -S: exercise automatic site initialization before the script runs. + self.run_child("""\ + import site + + assert site.getuserbase() == "~/.local", site.getuserbase() + """, no_site=False) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py b/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py index fdf49f6847..1434e5a962 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_sysconfig.py @@ -60,6 +60,18 @@ def test_platform_sysconfigdata(): assert sys.abiflags in sysconfig.get_config_var("INCLUDEPY") +@unittest.skipIf(sys.platform == "win32", "Windows has no system time zone database") +def test_tzpath_searches_system_time_zones(): + import sysconfig + tzpath = sysconfig.get_config_var("TZPATH") + assert tzpath == "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo", tzpath + import os + import subprocess + env = {k: v for k, v in os.environ.items() if k != "PYTHONTZPATH"} + out = subprocess.check_output([sys.executable, "-c", "import zoneinfo; print(':'.join(zoneinfo.TZPATH))"], env=env, text=True) + assert out.strip() == tzpath, out + + @unittest.skipUnless(sys.platform == "win32", "Windows-specific sysconfig behavior") def test_windows_libpython_is_not_exposed(): import sysconfig diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt index e3259b3eec..5e63c3f0e5 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncgen.txt @@ -14,8 +14,12 @@ test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_aiter_class @ darwin-arm64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_01 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_02 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_03 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_06 @ linux-x86_64 +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_07 @ linux-x86_64 +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_08 @ linux-x86_64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_10 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_11 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_aclose_12 @ linux-x86_64 test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_04 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_05 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_asyncgen.AsyncGenAsyncioTest.test_async_gen_asyncio_anext_06 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt index d9183e9829..6de50c6cd2 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_asyncio.txt @@ -190,13 +190,18 @@ test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete @ darwi test.test_asyncio.test_events.PollEventLoopTests.test_run_until_complete_stopped @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_server_close @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_ssl_connect_accepted_socket @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_close_after_finish @ linux-aarch64-github,linux-x86_64-github +# test_subprocess_close_after_finish, test_subprocess_wait_no_same_group (and the already excluded +# test_subprocess_exitcode) hang until the 600s timeout on the linux-amd64 and linux-aarch64 GitHub +# runners, and the first also fails in upstream's GitHub Actions runs. Root cause: they wait for a +# subprocess with no pipes, so only the SIGCHLD handler can wake the event loop, but +# signal.set_wakeup_fd is a stub in GraalPy and the handler never runs while the main thread is +# blocked in poll() unless the kernel happens to deliver the signal to that thread. A real +# implementation is in progress on branch fix/signal-set-wakeup-fd. test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exec_invalid_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github # GR-80225 !test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_exitcode @ darwin-arm64,linux-aarch64-github !test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_shell @ linux-aarch64-github,linux-x86_64 test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_shell_invalid_args @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_asyncio.test_events.PollEventLoopTests.test_subprocess_wait_no_same_group @ linux-aarch64-github test.test_asyncio.test_events.PollEventLoopTests.test_timeout_rounding @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_unclosed_pipe_transport @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_asyncio.test_events.PollEventLoopTests.test_write_pipe @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt index 577d7e5728..1d87d58c54 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_datetime.txt @@ -1038,10 +1038,13 @@ test.datetimetester.ZoneInfoTest[Africa/Cairo]_Pure.test_gaps @ darwin-arm64,dar test.datetimetester.ZoneInfoTest[Africa/Cairo]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +# The system-transition checks for the zones below compare the OS tzdata (/usr/share/zoneinfo) +# with the JDK tz rules that back time.localtime; they fail on the self-hosted GitHub runners +# whose tzdata (2026c) is newer than the labsjdk's, so they are not expected on the *-github tag sets. +test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/Casablanca]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Ceuta]_Fast.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github @@ -1084,10 +1087,10 @@ test.datetimetester.ZoneInfoTest[Africa/Douala]_Pure.test_gaps @ darwin-arm64,da test.datetimetester.ZoneInfoTest[Africa/Douala]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Fast.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[Africa/El_Aaiun]_Pure.test_system_transitions @ darwin-arm64,linux-aarch64,linux-x86_64 test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[Africa/Freetown]_Fast.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64 @@ -1592,11 +1595,11 @@ test.datetimetester.ZoneInfoTest[America/Dominica]_Pure.test_gaps @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Dominica]_Pure.test_system_transitions @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ linux-aarch64,linux-x86_64 !test.datetimetester.ZoneInfoTest[America/Edmonton]_Fast.test_system_transitions @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ linux-aarch64,linux-aarch64-github,linux-x86_64 +test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ linux-aarch64,linux-x86_64 !test.datetimetester.ZoneInfoTest[America/Edmonton]_Pure.test_system_transitions @ darwin-arm64 test.datetimetester.ZoneInfoTest[America/Eirunepe]_Fast.test_folds @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.datetimetester.ZoneInfoTest[America/Eirunepe]_Fast.test_gaps @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt index 9e9e08893b..e8b63d57ff 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_multiprocessing_spawn.txt @@ -60,7 +60,8 @@ test.test_multiprocessing_spawn.test_manager.WithManagerTestSemaphore.test_bound test.test_multiprocessing_spawn.test_manager.WithManagerTestSemaphore.test_semaphore @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.ChallengeResponseTest.test_challengeresponse @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.MiscTestCase.test__all__ @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github -test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_large_pool @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64-github +# GR-80580 +!test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_large_pool @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64-github test.test_multiprocessing_spawn.test_misc.MiscTestCase.test_spawn_sys_executable_none_allows_import @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.OtherTest.test_answer_challenge_auth_failure @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_multiprocessing_spawn.test_misc.OtherTest.test_deliver_challenge_auth_failure @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt index 12bb472039..9bf9d69335 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_os.txt @@ -81,7 +81,8 @@ test.test_os.FileTests.test_symlink_keywords @ darwin-arm64,linux-aarch64,linux- test.test_os.FileTests.test_write @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64-github test.test_os.FwalkTests.test_compare_to_walk @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_dir_fd @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github -test.test_os.FwalkTests.test_fd_finalization @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github +# Assumes stable lowest available FD; unrelated asynchronous finalizers can close descriptors between probes. +!test.test_os.FwalkTests.test_fd_finalization test.test_os.FwalkTests.test_fd_leak @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_file_like_path @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github test.test_os.FwalkTests.test_walk_above_recursion_limit @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java index 25f73178cd..54ddb4c584 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java @@ -27,7 +27,7 @@ import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_WIN32; import static com.oracle.graal.python.nodes.BuiltinNames.T__SIGNAL; -import static com.oracle.graal.python.nodes.StringLiterals.T_PY_EXTENSION; +import static com.oracle.graal.python.nodes.StringLiterals.J_PY_EXTENSION; import static com.oracle.graal.python.nodes.truffle.TruffleStringMigrationHelpers.isJavaString; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; @@ -103,9 +103,8 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.WindowsVersion; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; import com.oracle.graal.python.runtime.PythonImageBuildOptions; @@ -304,7 +303,7 @@ public static PlatformInfo getPlatformInfo() { public static final String MIME_TYPE = "text/x-python"; - public static final TruffleString[] T_DEFAULT_PYTHON_EXTENSIONS = new TruffleString[]{T_PY_EXTENSION, tsLiteral(".pyc")}; + public static final String[] T_DEFAULT_PYTHON_EXTENSIONS = new String[]{J_PY_EXTENSION, ".pyc"}; public static final TruffleLogger LOGGER = TruffleLogger.getLogger(ID, PythonLanguage.class); @@ -910,7 +909,7 @@ public static Source newSource(PythonContext ctxt, TruffleString tsrc, TruffleSt String src = tsrc.toJavaStringUncached(); if (mayBeFile) { try { - TruffleFile truffleFile = ctxt.getPublicTruffleFileRelaxed(name, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + TruffleFile truffleFile = ctxt.getPublicTruffleFileRelaxed(name.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); if (truffleFile.exists()) { // XXX: (tfel): We don't know if the expression has anything to do with the // filename that's given. We would really have to compare the entire @@ -1075,7 +1074,7 @@ public WindowsVersion getWindowsVersion(Node node) { CompilerDirectives.transferToInterpreterAndInvalidate(); assert !ImageInfo.inImageBuildtimeCode(); try { - windowsVersion = PosixSupportLibrary.getUncached().getWindowsVersion(PythonContext.get(node).getPosixSupport()); + windowsVersion = PythonContext.get(node).getPosixSupport().getWindowsVersion(); } catch (PosixException e) { EncapsulatingNodeReference encapsulating = EncapsulatingNodeReference.getCurrent(); Node previousNode = encapsulating.set(node); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java index 80d97b5b94..0269286bc3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java @@ -179,6 +179,7 @@ import com.oracle.graal.python.builtins.modules.io.BufferedWriterBuiltins; import com.oracle.graal.python.builtins.modules.io.BufferedWriterMixinBuiltins; import com.oracle.graal.python.builtins.modules.io.BytesIOBuiltins; +import com.oracle.graal.python.builtins.modules.io.CommonFileIOBuiltins; import com.oracle.graal.python.builtins.modules.io.FileIOBuiltins; import com.oracle.graal.python.builtins.modules.io.IOBaseBuiltins; import com.oracle.graal.python.builtins.modules.io.IOBaseDictBuiltins; @@ -188,6 +189,7 @@ import com.oracle.graal.python.builtins.modules.io.StringIOBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOBaseBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperBuiltins; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONEncoderBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONModuleBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONScannerBuiltins; @@ -632,7 +634,9 @@ private static PythonBuiltins[] initializeBuiltins(TruffleLanguage.Env env) { new BufferedReaderMixinBuiltins(), new BufferedWriterMixinBuiltins(), new BufferedIOMixinBuiltins(), + new CommonFileIOBuiltins(), new FileIOBuiltins(), + new WindowsConsoleIOBuiltins(), new TextIOWrapperBuiltins(), new IncrementalNewlineDecoderBuiltins(), new BufferedRWPairBuiltins(), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 416b1ccd48..a96555806d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -120,6 +120,7 @@ import com.oracle.graal.python.builtins.modules.io.IncrementalNewlineDecoderBuiltins; import com.oracle.graal.python.builtins.modules.io.StringIOBuiltins; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperBuiltins; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONEncoderBuiltins; import com.oracle.graal.python.builtins.modules.json.JSONScannerBuiltins; import com.oracle.graal.python.builtins.modules.lsprof.ProfilerBuiltins; @@ -921,7 +922,7 @@ It can be called either on the class (e.g. C.f()) or on an instance "BufferedRandom", PBufferedIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(BufferedReaderMixinBuiltins.SLOTS, BufferedIOMixinBuiltins.SLOTS, BufferedRandomBuiltins.SLOTS)), - PWindowsConsoleIO("_WindowsConsoleIO", PRawIOBase, newBuilder().moduleName("_io").basetype()), + PWindowsConsoleIO("_WindowsConsoleIO", PRawIOBase, newBuilder().moduleName("_io").basetype().addDict().slots(WindowsConsoleIOBuiltins.SLOTS)), PFileIO("FileIO", PRawIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(FileIOBuiltins.SLOTS)), PTextIOWrapper("TextIOWrapper", PTextIOBase, newBuilder().publishInModule("_io").basetype().addDict().slots(TextIOWrapperBuiltins.SLOTS)), PIncrementalNewlineDecoder("IncrementalNewlineDecoder", PythonObject, newBuilder().publishInModule("_io").basetype().slots(IncrementalNewlineDecoderBuiltins.SLOTS)), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java index aa7a0cec47..561fa5222b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BinasciiModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -409,10 +409,11 @@ abstract static class Crc32Node extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static long b2a(VirtualFrame frame, Object buffer, long crc, + @Bind Node inliningTarget, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib) { try { - return crc32((int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); + return crc32(inliningTarget, (int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); } finally { bufferLib.release(buffer, frame, callData); } @@ -432,10 +433,11 @@ abstract static class CrcHqxNode extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static long b2a(VirtualFrame frame, Object buffer, long crc, + @Bind Node inliningTarget, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib) { try { - return crcHqx((int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); + return crcHqx(inliningTarget, (int) crc, bufferLib.getInternalOrCopiedByteArray(buffer), 0, bufferLib.getBufferLength(buffer)); } finally { bufferLib.release(buffer, frame, callData); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index 51ac7a8a55..cd369906d2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -269,7 +269,6 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -1609,6 +1608,7 @@ static PNone printAllGiven(VirtualFrame frame, Object[] values, TruffleString se callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[i])); callWrite.execute(frame, writeMethod, sep); } + LoopNode.reportLoopCount(inliningTarget, values.length == 0 ? 0 : values.length - 1); if (lastValue >= 0) { callWrite.execute(frame, writeMethod, strNode.execute(frame, inliningTarget, values[lastValue])); } @@ -2480,7 +2480,7 @@ private static Object doInput(Object prompt, Node node, PythonContext context) { try { long fileno = PyLongAsLongNode.executeUncached(PyObjectCallMethodObjArgs.executeUncached(stdin, T_FILENO)); if (fileno == 0) { - tty = PosixSupportLibrary.getUncached().isatty(context.getPosixSupport(), 0); + tty = context.getPosixSupport().isatty(0); } } catch (AbstractTruffleException e) { // not a tty diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java index 2dabf1adad..188e65f357 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java @@ -150,6 +150,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -779,8 +780,9 @@ static PTuple lookup(VirtualFrame frame, Node inliningTarget, TruffleString enco } } else { Object[] searchPaths = getSearchPaths(context); - for (Object func : searchPaths) { - Object obj = callNode.executeObject(frame, func, normalizedEncoding); + int i = 0; + for (; i < searchPaths.length; i++) { + Object obj = callNode.executeObject(frame, searchPaths[i], normalizedEncoding); if (obj != PNone.NONE) { if (isTupleProfile.profile(inliningTarget, !isTupleInstanceCheck(frame, inliningTarget, obj, 4, typeCheck, sizeNode))) { throw raiseNode.raise(inliningTarget, TypeError, CODEC_SEARCH_MUST_RETURN_4); @@ -789,6 +791,7 @@ static PTuple lookup(VirtualFrame frame, Node inliningTarget, TruffleString enco break; } } + LoopNode.reportLoopCount(inliningTarget, i); } if (result != null) { putSearchPath(context, normalizedEncoding, result); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java index bccac49aa9..0c6321b671 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FaulthandlerModuleBuiltins.java @@ -86,8 +86,8 @@ import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.ExceptionUtils; @@ -104,7 +104,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -281,10 +280,9 @@ abstract static class SigSegvNode extends PythonUnaryClinicBuiltinNode { static PNone doIt(VirtualFrame frame, boolean releaseGil, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return raiseFatalSignal(frame, context, inliningTarget, posixLib, gil, constructAndRaiseNode, "SEGV", releaseGil); + return raiseFatalSignal(frame, context, inliningTarget, gil, constructAndRaiseNode, "SEGV", releaseGil); } @Override @@ -300,14 +298,13 @@ abstract static class SigAbrtNode extends PythonBuiltinNode { static PNone doIt(VirtualFrame frame, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return raiseFatalSignal(frame, context, inliningTarget, posixLib, gil, constructAndRaiseNode, "ABRT", false); + return raiseFatalSignal(frame, context, inliningTarget, gil, constructAndRaiseNode, "ABRT", false); } } - private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, Node inliningTarget, PosixSupportLibrary posixLib, GilNode gil, + private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, Node inliningTarget, GilNode gil, PConstructAndRaiseNode.Lazy constructAndRaiseNode, String signalName, boolean releaseGil) { try { int signum = SignalModuleBuiltins.signalFromName(context, signalName); @@ -315,7 +312,7 @@ private static PNone raiseFatalSignal(VirtualFrame frame, PythonContext context, gil.release(true); } try { - posixLib.signalSelf(context.getPosixSupport(), signum); + context.getPosixSupport().signalSelf(signum); } finally { if (releaseGil) { gil.acquire(); @@ -408,8 +405,8 @@ public void write(int b) { public void flush() throws IOException { super.flush(); try { - PosixSupportLibrary.getUncached().write(PythonContext.get(null).getPosixSupport(), fd, PosixSupportLibrary.Buffer.wrap(bb.toArray())); - } catch (PosixSupportLibrary.PosixException e) { + PythonContext.get(null).getPosixSupport().write(fd, PosixSupport.Buffer.wrap(bb.toArray())); + } catch (PosixSupport.PosixException e) { // Ignore } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java index caca032aba..efd562580e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java @@ -80,8 +80,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixConstants.IntConstant; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -135,11 +134,10 @@ protected ArgumentClinicProvider getArgumentClinic() { synchronized PNone flock(VirtualFrame frame, int fd, int operation, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posix, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_FCNTL_FLOCK, fd, operation); try { - posix.flock(getPosixSupport(), fd, operation); + getPosixSupport().flock(fd, operation); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -157,7 +155,6 @@ abstract static class LockfNode extends PythonClinicBuiltinNode { PNone lockf(VirtualFrame frame, int fd, int code, Object lenObj, Object startObj, int whence, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posix, @Cached PyLongAsLongNode asLongNode, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -181,7 +178,7 @@ PNone lockf(VirtualFrame frame, int fd, int code, Object lenObj, Object startObj len = asLongNode.execute(frame, inliningTarget, lenObj); } try { - posix.fcntlLock(getPosixSupport(), fd, (code & LOCK_NB.value) == 0, lockType, whence, start, len); + getPosixSupport().fcntlLock(fd, (code & LOCK_NB.value) == 0, lockType, whence, start, len); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -206,7 +203,6 @@ abstract static class IoctlNode extends PythonClinicBuiltinNode { Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutateArg, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary acquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached("createFor($node)") InteropCallData callData, @@ -262,7 +258,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat bufferLib.readIntoByteArray(buffer, 0, ioctlArg, 0, len); } try { - int ret = callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, releaseGil, posixLib, gilNode, constructAndRaiseNode); + int ret = callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, releaseGil, gilNode, constructAndRaiseNode); if (writable && mutateArg) { return ret; } else { @@ -294,7 +290,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat } byte[] ioctlArg = new byte[len + 1]; copyToByteArrayNode.execute(stringArg, 0, ioctlArg, 0, len, utf8); - callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, true, posixLib, gilNode, constructAndRaiseNode); + callIoctlBytes(frame, inliningTarget, fd, request, ioctlArg, true, gilNode, constructAndRaiseNode); return PFactory.createBytes(context.getLanguage(inliningTarget), ioctlArg, len); } @@ -307,7 +303,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat try { gilNode.release(true); try { - return posixLib.ioctlInt(getPosixSupport(), fd, request, intArg); + return getPosixSupport().ioctlInt(fd, request, intArg); } finally { gilNode.acquire(); } @@ -316,14 +312,14 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat } } - private int callIoctlBytes(VirtualFrame frame, Node inliningTarget, int fd, long request, byte[] ioctlArg, boolean releaseGil, PosixSupportLibrary posixLib, GilNode gilNode, + private int callIoctlBytes(VirtualFrame frame, Node inliningTarget, int fd, long request, byte[] ioctlArg, boolean releaseGil, GilNode gilNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (releaseGil) { gilNode.release(true); } try { - return posixLib.ioctlBytes(getPosixSupport(), fd, request, ioctlArg); + return getPosixSupport().ioctlBytes(fd, request, ioctlArg); } finally { if (releaseGil) { gilNode.acquire(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java index 9c163df123..796cecdbba 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalPythonModuleBuiltins.java @@ -165,7 +165,6 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; -import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.nodes.util.ToNativePrimitiveStorageNode; import com.oracle.graal.python.pegparser.InputType; import com.oracle.graal.python.runtime.ExecutionContext; @@ -173,7 +172,6 @@ import com.oracle.graal.python.runtime.ExecutionContext.InteropCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonImageBuildOptions; import com.oracle.graal.python.runtime.PythonOptions; @@ -407,7 +405,7 @@ private void runFile(PythonContext context, TruffleString inputFilePath) { source = builder.build(); // TODO we should handle non-IO errors better } catch (IOException e) { - ErrorAndMessagePair error = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached()); + ErrorAndMessagePair error = OSErrorEnum.fromException(e); String msg = String.format("%s: can't open file '%s': [Errno %d] %s\n", context.getOption(PythonOptions.Executable), inputFilePath, error.oserror.getNumber(), error.message); // CPython uses fprintf(stderr, ...) try { @@ -630,19 +628,18 @@ private static Object doLoadBytecodeFile(Object bytecodePath, Object sourcePath, @GenerateNodeFactory public abstract static class ReadFileNode extends PythonUnaryBuiltinNode { @Specialization - PBytes doString(VirtualFrame frame, Object filenameObj, + static PBytes doString(VirtualFrame frame, Object filenameObj, @Bind Node inliningTarget, @Bind PythonContext context, - @Cached CastToTruffleStringNode castToTruffleStringNode, - @Cached TruffleString.EqualNode eqNode, + @Cached CastToJavaStringNode castToStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - TruffleString filename = castToTruffleStringNode.execute(inliningTarget, filenameObj); + String filename = castToStringNode.execute(filenameObj); TruffleFile file = context.getPublicTruffleFileRelaxed(filename, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); byte[] bytes = file.readAllBytes(); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (Exception ex) { - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(ex, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(ex); throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, errAndMsg.oserror.getNumber(), errAndMsg.message); } } @@ -972,9 +969,8 @@ static boolean isAvailable(@Bind PythonContext context) { @GenerateNodeFactory public abstract static class PosixModuleBackendNode extends PythonBuiltinNode { @Specialization - TruffleString posixModuleBackend( - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getBackend(getPosixSupport()); + TruffleString posixModuleBackend() { + return getPosixSupport().getBackend(); } } @@ -1251,7 +1247,6 @@ abstract static class DumpHeapNode extends PythonBuiltinNode { TruffleString doit(VirtualFrame frame, @Bind Node inliningTarget, @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { TruffleFile tempFile; try { @@ -1259,7 +1254,7 @@ TruffleString doit(VirtualFrame frame, tempFile = context.getEnv().createTempFile(context.getEnv().getCurrentWorkingDirectory(), J_GRAALPYTHON_ID, ".hprof"); tempFile.delete(); } catch (IOException e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } PythonUtils.dumpHeap(tempFile.getPath()); return fromJavaStringNode.execute(tempFile.getPath(), TS_ENCODING); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java index 25c615978c..d691dc79f4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ImpModuleBuiltins.java @@ -888,7 +888,7 @@ private static Object doCreate(PythonObject moduleSpec, Node inliningTarget, Pyt } catch (ImportException ie) { throw ie.reraise(); } catch (IOException e) { - throw PConstructAndRaiseNode.getUncached().raiseOSError(null, e, TruffleString.EqualNode.getUncached()); + throw PConstructAndRaiseNode.getUncached().raiseOSError(null, e); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java index 8650f46bf0..3ab1107790 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ItertoolsModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -57,6 +57,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -159,6 +160,7 @@ static Object tee(VirtualFrame frame, Object iterable, int n, for (int i = 1; i < n; i++) { tupleObjs[i] = TeeBuiltins.CopyNode.copy(to, language); } + LoopNode.reportLoopCount(inliningTarget, n - 1); return PFactory.createTuple(language, tupleObjs); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java index 07dad36ccb..8d9a97fb34 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JArrayModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -84,6 +84,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(defineModule = "jarray") @@ -227,6 +228,7 @@ static Object fromSequence(PSequence sequence, Object type, throw CompilerDirectives.shouldNotReachHere("failed to set array item"); } } + LoopNode.reportLoopCount(inliningTarget, length); return array; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java index 619cb9dc1d..ae410da54a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -99,7 +99,7 @@ @CoreFunctions(defineModule = J_JAVA) public final class JavaModuleBuiltins extends PythonBuiltins { - private static final TruffleString T_JAR = tsLiteral(".jar"); + private static final String J_JAR = ".jar"; @Override protected List> getNodeFactories() { @@ -159,9 +159,11 @@ abstract static class AddToClassPathNode extends PythonBuiltinNode { @Specialization static PNone add(Object[] args, @Bind Node inliningTarget, + @Bind PythonContext context, @Cached CastToTruffleStringNode castToString, + @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached PRaiseNode raiseNode) { - Env env = PythonContext.get(inliningTarget).getEnv(); + Env env = context.getEnv(); if (!env.isHostLookupAllowed()) { throw raiseNode.raise(inliningTarget, PythonErrorType.NotImplementedError, ErrorMessages.HOST_ACCESS_NOT_ALLOWED); } @@ -172,7 +174,8 @@ static PNone add(Object[] args, entry = castToString.execute(inliningTarget, arg); // Always allow accessing JAR files in the language home; folders are allowed // implicitly - env.addToHostClassPath(PythonContext.get(inliningTarget).getPublicTruffleFileRelaxed(entry, T_JAR)); + String jEntry = toJavaStringNode.execute(entry); + env.addToHostClassPath(context.getPublicTruffleFileRelaxed(jEntry, J_JAR)); } catch (CannotCastException e) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.CLASSPATH_ARG_MUST_BE_STRING, i + 1, arg); } catch (SecurityException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java index a5ee509dec..029f6ac3cf 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java @@ -954,6 +954,7 @@ public abstract static class GcdNode extends PythonVarargsBuiltinNode { @Specialization(guards = {"args.length > 1", "keywords.length == 0"}) public static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object self, Object[] args, @SuppressWarnings("unused") PKeyword[] keywords, + @Bind Node inliningTarget, @Cached Gcd2Node gdcNode, @Cached LoopConditionProfile profile) { Object res = args[0]; @@ -961,6 +962,7 @@ public static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object for (int i = 1; profile.inject(i < args.length); i++) { res = gdcNode.execute(frame, res, args[i]); } + LoopNode.reportLoopCount(inliningTarget, args.length - 1); return res; } @@ -1116,6 +1118,7 @@ static Object gcd(VirtualFrame frame, @SuppressWarnings("unused") Object self, O Object m = mulNode.execute(frame, f, b); a = absNode.execute(frame, m); } + LoopNode.reportLoopCount(inliningTarget, args.length - 1); return a; } @@ -2342,6 +2345,7 @@ public double hypot2(VirtualFrame frame, @SuppressWarnings("unused") Object self } coordinates[i] = x; } + LoopNode.reportLoopCount(inliningTarget, arguments.length); if (Double.isInfinite(max)) { return max; } @@ -2364,6 +2368,7 @@ public double hypot2(VirtualFrame frame, @SuppressWarnings("unused") Object self csum += x; frac += (oldcsum - csum) + x; } + LoopNode.reportLoopCount(inliningTarget, arguments.length); return max * Math.sqrt(csum - 1.0 + frac); } } @@ -2824,6 +2829,7 @@ static double doGeneric(VirtualFrame frame, Object p, Object q, max = x; } } + LoopNode.reportLoopCount(inliningTarget, len); if (infProfile.profile(inliningTarget, Double.isInfinite(max))) { return max; } @@ -2845,6 +2851,7 @@ static double doGeneric(VirtualFrame frame, Object p, Object q, csum += x; frac += (oldcsum - csum) + x; } + LoopNode.reportLoopCount(inliningTarget, len); return max * Math.sqrt(csum - 1.0 + frac); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java index 69d21c7834..d89c46b6fe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java @@ -59,14 +59,13 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -102,18 +101,17 @@ public abstract static class LockingNode extends PythonTernaryClinicBuiltinNode Object locking(VirtualFrame frame, int fd, int mode, long nbytes, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gilNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_LOCKING, fd, mode, nbytes); try { gilNode.release(true); try { - posixLib.msvcrtLocking(getPosixSupport(), fd, mode, nbytes); + getPosixSupport().msvcrtLocking(fd, mode, nbytes); } finally { gilNode.acquire(); } - } catch (PosixSupportLibrary.PosixException e) { + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; @@ -133,11 +131,10 @@ public abstract static class SetModeNode extends PythonBinaryClinicBuiltinNode { @Specialization int setMode(VirtualFrame frame, int fd, int flags, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.setMode(getPosixSupport(), fd, flags); - } catch (PosixSupportLibrary.PosixException e) { + return getPosixSupport().setMode(fd, flags); + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -156,12 +153,11 @@ public abstract static class GetOsfHandleNode extends PythonUnaryClinicBuiltinNo long getOsfHandle(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_GET_OSFHANDLE, fd); try { - return posixLib.getOsfHandle(getPosixSupport(), fd); - } catch (PosixSupportLibrary.PosixException e) { + return getPosixSupport().getOsfHandle(fd); + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -181,12 +177,11 @@ public abstract static class OpenOsfHandleNode extends PythonBinaryClinicBuiltin int openOsfHandle(VirtualFrame frame, long handle, int flags, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_MSVCRT_OPEN_OSFHANDLE, handle, flags); try { - return posixLib.openOsfHandle(getPosixSupport(), handle, flags); - } catch (PosixSupportLibrary.PosixException e) { + return getPosixSupport().openOsfHandle(handle, flags); + } catch (PosixSupport.PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java index 237185e05a..2c62d1340b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/NtModuleBuiltins.java @@ -64,7 +64,7 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -121,11 +121,13 @@ private TruffleString getTruffleStringPath(String fspath) { abstract static class PathSplitRootNode extends PythonUnaryClinicBuiltinNode { @Specialization @TruffleBoundary - Object splitroot(PosixPath path) { + Object splitroot(PosixPath path, + @Bind Node inliningTarget, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode) { // TODO should call WINAPI PathCchSkipRoot PythonLanguage language = PythonLanguage.get(null); - TruffleString pathString = PosixSupportLibrary.getUncached().getPathAsString(getPosixSupport(), path.value); + TruffleString pathString = getPathAsStringNode.execute(inliningTarget, getPosixSupport(), path.value); int len = pathString.codePointLengthUncached(TS_ENCODING); int index = pathString.indexOfCodePointUncached(':', 0, len, TS_ENCODING); if (index <= 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index a0ba1abd22..c474896891 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -102,6 +102,7 @@ import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.nodes.PGuards; +import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.builtins.TupleNodes; import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode; @@ -118,17 +119,18 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CastToJavaLongLossyNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; +import com.oracle.graal.python.nodes.util.PosixSupportNodes.DecodeFilesystemStringNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixConstants.IntConstant; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.OpenPtyResult; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -147,6 +149,7 @@ import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Idempotent; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; @@ -154,6 +157,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -326,12 +330,12 @@ public void initialize(Python3Core core) { public void postInitialize(Python3Core core) { super.postInitialize(core); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - Object posixSupport = core.getContext().getPosixSupport(); + PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonModule posix = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 - ? core.lookupBuiltinModule(T_NT) : core.lookupBuiltinModule(T_POSIX); + ? core.lookupBuiltinModule(T_NT) + : core.lookupBuiltinModule(T_POSIX); - if (posixLib.getBackend(posixSupport).toJavaStringUncached().equals("java")) { + if (posixSupport.getBackend().toJavaStringUncached().equals("java")) { posix.setAttribute(toTruffleStringUncached("geteuid"), PNone.NO_VALUE); posix.setAttribute(toTruffleStringUncached("getegid"), PNone.NO_VALUE); posix.setAttribute(toTruffleStringUncached("WNOHANG"), EMULATED_WNOHANG); @@ -353,8 +357,7 @@ public void patchPostInitialize(Python3Core core) { } private void populateEnviron(Python3Core core) { - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - Object posixSupport = core.getContext().getPosixSupport(); + PosixSupport posixSupport = core.getContext().getPosixSupport(); PythonLanguage language = core.getLanguage(); Map getenv = core.getContext().getEnv().getEnvironment(); @@ -378,13 +381,13 @@ private void populateEnviron(Python3Core core) { Object k; Object v; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - k = posixLib.createWideStringFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = posixLib.createWideStringFromString(posixSupport, value); + k = PosixSupportNodes.CreateWideStringFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.CreateWideStringFromStringNode.executeUncached(posixSupport, value); } else { - k = posixLib.createPathFromString(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); - v = posixLib.createPathFromString(posixSupport, value); + k = PosixSupportNodes.CreatePathFromStringNode.executeUncached(posixSupport, toTruffleStringUncached(pyenvLauncherKey)); + v = PosixSupportNodes.CreatePathFromStringNode.executeUncached(posixSupport, value); } - posixLib.setenv(posixSupport, k, v, true); + posixSupport.setenv(k, v, true); } catch (PosixException ignored) { } val = toEnv(language, value); @@ -444,9 +447,9 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { // Unlike in other posix builtins, we go through str -> bytes -> byte[] -> String @@ -458,19 +461,19 @@ static PNone putenv(VirtualFrame frame, Object nameObject, Object valueObject, if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; TruffleString value = (TruffleString) valueObject; - nameOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(posixSupport, name), raiseNode); - valueOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(posixSupport, value), raiseNode); + nameOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, posixSupport, name), raiseNode); + valueOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, posixSupport, value), raiseNode); checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); byte[] value = toBytesNode.execute((PBytes) valueObject); - nameOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(posixSupport, name), raiseNode); - valueOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(posixSupport, value), raiseNode); + nameOpaque = checkNull(inliningTarget, posixSupport.createCStringFromBytes(name), raiseNode); + valueOpaque = checkNull(inliningTarget, posixSupport.createCStringFromBytes(value), raiseNode); checkEqualSign(inliningTarget, name, raiseNode); } auditNode.audit(frame, inliningTarget, T_OS_PUTENV, nameObject, valueObject); try { - posixLib.setenv(posixSupport, nameOpaque, valueOpaque, true); + posixSupport.setenv(nameOpaque, valueOpaque, true); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -490,6 +493,7 @@ private static void checkEqualSign(Node inliningTarget, byte[] bytes, PRaiseNode throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ILLEGAL_ENVIRONMENT_VARIABLE_NAME); } } + LoopNode.reportLoopCount(inliningTarget, bytes.length); } private static void checkWindowsEnvName(Node inliningTarget, TruffleString name, TruffleString.CodePointLengthNode codePointLengthNode, @@ -521,22 +525,22 @@ static PNone putenv(VirtualFrame frame, Object nameObject, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object nameOpaque; if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { TruffleString name = (TruffleString) nameObject; - nameOpaque = checkNull(inliningTarget, posixLib.createWideStringFromString(context.getPosixSupport(), name), raiseNode); + nameOpaque = checkNull(inliningTarget, createWideStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), name), raiseNode); PutenvNode.checkWindowsEnvName(inliningTarget, name, codePointLengthNode, indexOfCodePointNode, raiseNode); } else { byte[] name = toBytesNode.execute((PBytes) nameObject); - nameOpaque = checkNull(inliningTarget, posixLib.createCStringFromBytes(context.getPosixSupport(), name), raiseNode); + nameOpaque = checkNull(inliningTarget, context.getPosixSupport().createCStringFromBytes(name), raiseNode); } auditNode.audit(frame, inliningTarget, T_OS_UNSETENV, nameObject); try { - posixLib.unsetenv(context.getPosixSupport(), nameOpaque); + context.getPosixSupport().unsetenv(nameOpaque); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -565,12 +569,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile isPListProfile, @Cached TupleNodes.GetTupleStorage getTupleStorage, @Cached PyTupleCheckNode tupleCheckNode, @Cached ToArrayNode toArrayNode, @Cached ObjectToOpaquePathNode toOpaquePathNode, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -592,16 +596,17 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, Object[] opaqueArgs = new Object[args.length]; for (int i = 0; i < args.length; ++i) { Object opaquePath = toOpaquePathNode.execute(frame, inliningTarget, args[i], i == 0); - Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), opaquePath); - opaqueArgs[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); + Buffer bytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), opaquePath); + opaqueArgs[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } + LoopNode.reportLoopCount(inliningTarget, args.length); // TODO ValueError "execv() arg 2 first element cannot be empty" auditNode.audit(frame, inliningTarget, T_OS_EXEC, path.originalObject, argv, PNone.NONE); gil.release(true); try { - posixLib.execv(context.getPosixSupport(), path.value, opaqueArgs); + context.getPosixSupport().execv(path.value, opaqueArgs); } catch (PosixException e) { gil.acquire(); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -616,9 +621,8 @@ static Object execvArgs(VirtualFrame frame, PosixPath path, Object argv, @GenerateNodeFactory public abstract static class GetPidNode extends PythonBuiltinNode { @Specialization - static long getPid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getpid(context.getPosixSupport()); + static long getPid(@Bind PythonContext context) { + return context.getPosixSupport().getpid(); } } @@ -626,9 +630,8 @@ static long getPid(@Bind PythonContext context, @GenerateNodeFactory public abstract static class GetUidNode extends PythonBuiltinNode { @Specialization - static long getUid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getuid(context.getPosixSupport()); + static long getUid(@Bind PythonContext context) { + return context.getPosixSupport().getuid(); } } @@ -638,10 +641,9 @@ public abstract static class GetEUidNode extends PythonBuiltinNode { @Specialization static long getUid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.geteuid(context.getPosixSupport()); + return context.getPosixSupport().geteuid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -652,9 +654,8 @@ static long getUid(@Bind Node inliningTarget, @GenerateNodeFactory public abstract static class GetGidNode extends PythonBuiltinNode { @Specialization - static long getGid(@Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.getgid(context.getPosixSupport()); + static long getGid(@Bind PythonContext context) { + return context.getPosixSupport().getgid(); } } @@ -664,10 +665,9 @@ public abstract static class GetEGidNode extends PythonBuiltinNode { @Specialization static long getGid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getegid(context.getPosixSupport()); + return context.getPosixSupport().getegid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -680,10 +680,9 @@ public abstract static class GetPpidNode extends PythonBuiltinNode { @Specialization static long getPpid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getppid(context.getPosixSupport()); + return context.getPosixSupport().getppid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -730,10 +729,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long getPgid(VirtualFrame frame, long pid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getpgid(context.getPosixSupport(), pid); + return context.getPosixSupport().getpgid(pid); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -754,10 +752,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object setPgid(VirtualFrame frame, long pid, long pgid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setpgid(context.getPosixSupport(), pid, pgid); + context.getPosixSupport().setpgid(pid, pgid); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -772,10 +769,9 @@ public abstract static class SetPgrpdNode extends PythonBuiltinNode { static Object getPpid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setpgid(context.getPosixSupport(), 0, 0); + context.getPosixSupport().setpgid(0, 0); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -789,10 +785,9 @@ public abstract static class GetPgrpNode extends PythonBuiltinNode { @Specialization static long getPpid(@Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getpgrp(context.getPosixSupport()); + return context.getPosixSupport().getpgrp(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -812,10 +807,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long getSid(VirtualFrame frame, long pid, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getsid(context.getPosixSupport(), pid); + return context.getPosixSupport().getsid(pid); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -830,10 +824,9 @@ public abstract static class SetSidNode extends PythonBuiltinNode { static Object setsid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setsid(context.getPosixSupport()); + context.getPosixSupport().setsid(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -848,10 +841,9 @@ abstract static class GetGroupsNode extends PythonBuiltinNode { static Object getgroups(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] groups = posixLib.getgroups(context.getPosixSupport()); + long[] groups = context.getPosixSupport().getgroups(); return PFactory.createList(context.getLanguage(inliningTarget), new LongSequenceStorage(groups)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -867,12 +859,11 @@ public abstract static class OpenPtyNode extends PythonBuiltinNode { static Object openpty(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - OpenPtyResult result = posixLib.openpty(context.getPosixSupport()); - posixLib.setInheritable(context.getPosixSupport(), result.masterFd(), false); - posixLib.setInheritable(context.getPosixSupport(), result.slaveFd(), false); + OpenPtyResult result = context.getPosixSupport().openpty(); + context.getPosixSupport().setInheritable(result.masterFd(), false); + context.getPosixSupport().setInheritable(result.slaveFd(), false); return PFactory.createTuple(context.getLanguage(inliningTarget), new int[]{result.masterFd(), result.slaveFd()}); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -897,7 +888,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static int open(VirtualFrame frame, PosixPath path, int flags, int mode, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @@ -911,7 +901,7 @@ static int open(VirtualFrame frame, PosixPath path, int flags, int mode, int dir try { while (true) { try { - return posixLib.openat(context.getPosixSupport(), dirFd, path.value, fixedFlags, mode); + return context.getPosixSupport().openat(dirFd, path.value, fixedFlags, mode); } catch (PosixException e) { errorProfile.enter(inliningTarget); if (e.hasErrno(OSErrorEnum.EINTR)) { @@ -942,13 +932,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone close(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } @@ -974,17 +963,16 @@ protected ArgumentClinicProvider getArgumentClinic() { static PBytes doRead(VirtualFrame frame, int fd, int length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile1, @Cached InlinedBranchProfile errorProfile2, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (length < 0) { int error = OSErrorEnum.EINVAL.getNumber(); - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, posixLib.strerror(context.getPosixSupport(), error)); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, context.getPosixSupport().strerror(error)); } try { - return read(fd, length, inliningTarget, posixLib, context.getPosixSupport(), errorProfile1, gil); + return read(fd, length, inliningTarget, context.getPosixSupport(), errorProfile1, gil); } catch (PosixException e) { errorProfile2.enter(inliningTarget); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -993,14 +981,13 @@ static PBytes doRead(VirtualFrame frame, int fd, int length, public static PBytes read(int fd, int length, Node inliningTarget, - PosixSupportLibrary posixLib, PosixSupport posixSupport, InlinedBranchProfile errorProfile, GilNode gil) throws PosixException { gil.release(true); try { while (true) { try { - Buffer result = posixLib.read(posixSupport, fd, length); + Buffer result = posixSupport.read(fd, length); if (result.length > Integer.MAX_VALUE) { // sanity check that it is safe to cast result.length to int, to be // removed once we support large arrays @@ -1039,12 +1026,11 @@ static long doWrite(VirtualFrame frame, int fd, Object dataBuffer, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("dataBuffer") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return write(fd, bufferLib.getInternalOrCopiedByteArray(dataBuffer), bufferLib.getBufferLength(dataBuffer), inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil); + return write(fd, bufferLib.getInternalOrCopiedByteArray(dataBuffer), bufferLib.getBufferLength(dataBuffer), inliningTarget, context.getPosixSupport(), errorProfile, gil); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { @@ -1053,13 +1039,13 @@ static long doWrite(VirtualFrame frame, int fd, Object dataBuffer, } public static long write(int fd, byte[] dataBytes, - int dataLen, Node inliningTarget, PosixSupportLibrary posixLib, PosixSupport posixSupport, + int dataLen, Node inliningTarget, PosixSupport posixSupport, InlinedBranchProfile errorProfile, GilNode gil) throws PosixException { gil.release(true); try { while (true) { try { - return posixLib.write(posixSupport, fd, new Buffer(dataBytes, dataLen)); + return posixSupport.write(fd, new Buffer(dataBytes, dataLen)); } catch (PosixErrnoException e) { errorProfile.enter(inliningTarget); if (e.hasErrno(OSErrorEnum.EINTR)) { @@ -1089,10 +1075,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static int dup(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.dup(context.getPosixSupport(), fd); + return context.getPosixSupport().dup(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1115,17 +1100,16 @@ protected ArgumentClinicProvider getArgumentClinic() { static int dup2(VirtualFrame frame, int fd, int fd2, boolean inheritable, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (fd < 0 || fd2 < 0) { // CPython does not set errno here and raises a 'random' OSError // (possibly with errno=0 Success) int error = OSErrorEnum.EINVAL.getNumber(); - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, posixLib.strerror(context.getPosixSupport(), error)); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, error, context.getPosixSupport().strerror(error)); } try { - return posixLib.dup2(context.getPosixSupport(), fd, fd2, inheritable); + return context.getPosixSupport().dup2(fd, fd2, inheritable); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1146,10 +1130,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean getInheritable(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getInheritable(context.getPosixSupport(), fd); + return context.getPosixSupport().getInheritable(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1171,11 +1154,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone setInheritable(VirtualFrame frame, int fd, int inheritable, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { // not sure why inheritable is not a boolean, but that is how they do it in CPython - posixLib.setInheritable(context.getPosixSupport(), fd, inheritable != 0); + context.getPosixSupport().setInheritable(fd, inheritable != 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1192,12 +1174,11 @@ static PTuple pipe(VirtualFrame frame, @Bind Node inliningTarget, @Cached GilNode gil, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int[] pipe; gil.release(true); try { - pipe = posixLib.pipe(context.getPosixSupport()); + pipe = context.getPosixSupport().pipe(); } catch (PosixException e) { gil.acquire(); // need to acquire the gil to construct the OSError object throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1238,10 +1219,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static long lseek(VirtualFrame frame, int fd, long pos, int how, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.lseek(context.getPosixSupport(), fd, pos, mapPythonSeekWhenceToPosix(how)); + return context.getPosixSupport().lseek(fd, pos, mapPythonSeekWhenceToPosix(how)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1263,7 +1243,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone ftruncate(VirtualFrame frame, int fd, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached InlinedBranchProfile errorProfile, @@ -1273,7 +1252,7 @@ static PNone ftruncate(VirtualFrame frame, int fd, long length, try { gil.release(true); try { - posixLib.ftruncate(context.getPosixSupport(), fd, length); + context.getPosixSupport().ftruncate(fd, length); } finally { gil.acquire(); } @@ -1305,7 +1284,6 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone truncate(VirtualFrame frame, PosixPath path, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Exclusive @Cached GilNode gil, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -1313,7 +1291,7 @@ static PNone truncate(VirtualFrame frame, PosixPath path, long length, try { gil.release(true); try { - posixLib.truncate(context.getPosixSupport(), path.value, length); + context.getPosixSupport().truncate(path.value, length); } finally { gil.acquire(); } @@ -1327,12 +1305,11 @@ static PNone truncate(VirtualFrame frame, PosixPath path, long length, static PNone ftruncate(VirtualFrame frame, PosixFd fd, long length, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Exclusive @Cached GilNode gil, @Exclusive @Cached InlinedBranchProfile errorProfile, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return FtruncateNode.ftruncate(frame, fd.fd, length, inliningTarget, context, posixLib, auditNode, gil, errorProfile, constructAndRaiseNode); + return FtruncateNode.ftruncate(frame, fd.fd, length, inliningTarget, context, auditNode, gil, errorProfile, constructAndRaiseNode); } } @@ -1350,12 +1327,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone fsync(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - posixLib.fsync(context.getPosixSupport(), fd); + context.getPosixSupport().fsync(fd); return PNone.NONE; } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -1383,10 +1359,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean getBlocking(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getBlocking(context.getPosixSupport(), fd); + return context.getPosixSupport().getBlocking(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1408,10 +1383,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone setBlocking(VirtualFrame frame, int fd, boolean blocking, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setBlocking(context.getPosixSupport(), fd, blocking); + context.getPosixSupport().setBlocking(fd, blocking); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1433,11 +1407,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple getTerminalSize(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // TODO default value should be fileno(stdout) try { - int[] result = posixLib.getTerminalSize(context.getPosixSupport(), fd); + int[] result = context.getPosixSupport().getTerminalSize(fd); return PFactory.createStructSeq(context.getLanguage(inliningTarget), TERMINAL_SIZE_DESC, result[0], result[1]); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1461,11 +1434,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatPath(VirtualFrame frame, PosixPath path, int dirFd, boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("positive") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] out = posixLib.fstatat(context.getPosixSupport(), dirFd, path.value, followSymlinks); + long[] out = context.getPosixSupport().fstatat(dirFd, path.value, followSymlinks); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1490,11 +1462,10 @@ static PTuple doStatFdWithFollowSymlinks(VirtualFrame frame, PosixFd fd, int dir static PTuple doStatFd(VirtualFrame frame, PosixFd fd, @SuppressWarnings("unused") int dirFd, @SuppressWarnings("unused") boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("positive") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - long[] out = posixLib.fstat(context.getPosixSupport(), fd.fd); + long[] out = context.getPosixSupport().fstat(fd.fd); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); @@ -1521,12 +1492,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatPath(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { // TODO we used to return all zeros when the filename was equal to sys.executable - long[] out = posixLib.fstatat(context.getPosixSupport(), dirFd, path.value, false); + long[] out = context.getPosixSupport().fstatat(dirFd, path.value, false); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -1548,13 +1518,12 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatFd(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - long[] out = posixLib.fstat(context.getPosixSupport(), fd); + long[] out = context.getPosixSupport().fstat(fd); return createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, out); } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -1590,16 +1559,15 @@ protected ArgumentClinicProvider getArgumentClinic() { static PTuple doStatvfs(VirtualFrame frame, PosixFileHandle posixFileHandle, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile posixPathProfile, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] out; try { if (posixPathProfile.profile(inliningTarget, posixFileHandle instanceof PosixPath)) { - out = posixLib.statvfs(context.getPosixSupport(), ((PosixPath) posixFileHandle).value); + out = context.getPosixSupport().statvfs(((PosixPath) posixFileHandle).value); } else { - out = posixLib.fstatvfs(context.getPosixSupport(), ((PosixFd) posixFileHandle).fd); + out = context.getPosixSupport().fstatvfs(((PosixFd) posixFileHandle).fd); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, posixFileHandle.originalObject); @@ -1617,12 +1585,11 @@ abstract static class FStatvfsNode extends PythonUnaryClinicBuiltinNode { static PTuple doStatvfs(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile positiveLongProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] out; try { - out = posixLib.fstatvfs(context.getPosixSupport(), fd); + out = context.getPosixSupport().fstatvfs(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd); } @@ -1644,10 +1611,9 @@ abstract static class UnameNode extends PythonBuiltinNode { static PTuple uname(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return PFactory.createStructSeq(context.getLanguage(inliningTarget), UNAME_RESULT_DESC, posixLib.uname(context.getPosixSupport())); + return PFactory.createStructSeq(context.getLanguage(inliningTarget), UNAME_RESULT_DESC, context.getPosixSupport().uname()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1668,13 +1634,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone unlink(VirtualFrame frame, PosixPath path, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_REMOVE, path.originalObject, dirFdForAudit(dirFd)); try { - posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, false); + context.getPosixSupport().unlinkat(dirFd, path.value, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1715,10 +1680,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone link(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, boolean followSymlinks, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.linkat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value, followSymlinks ? AT_SYMLINK_FOLLOW.value : 0); + context.getPosixSupport().linkat(srcDirFd, src.value, dstDirFd, dst.value, followSymlinks ? AT_SYMLINK_FOLLOW.value : 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -1743,10 +1707,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone symlink(VirtualFrame frame, PosixPath src, PosixPath dst, @SuppressWarnings("unused") boolean targetIsDir, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.symlinkat(context.getPosixSupport(), src.value, dirFd, dst.value); + context.getPosixSupport().symlinkat(src.value, dirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -1769,13 +1732,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone mkdir(VirtualFrame frame, PosixPath path, int mode, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_MKDIR, path.originalObject, mode, dirFdForAudit(dirFd)); try { - posixLib.mkdirat(context.getPosixSupport(), dirFd, path.value, mode); + context.getPosixSupport().mkdirat(dirFd, path.value, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1797,13 +1759,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone rmdir(VirtualFrame frame, PosixPath path, int dirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RMDIR, path.originalObject, dirFdForAudit(dirFd)); try { - posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, true); + context.getPosixSupport().unlinkat(dirFd, path.value, true); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1818,10 +1779,10 @@ abstract static class GetcwdNode extends PythonBuiltinNode { static TruffleString getcwd(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.getPathAsString(context.getPosixSupport(), posixLib.getcwd(context.getPosixSupport())); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().getcwd()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1835,11 +1796,11 @@ abstract static class GetcwdbNode extends PythonBuiltinNode { static PBytes getcwdb(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object path = posixLib.getcwd(context.getPosixSupport()); - return opaquePathToBytes(path, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + Object path = context.getPosixSupport().getcwd(); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), path, context.getLanguage(inliningTarget)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1860,10 +1821,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone chdirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.chdir(context.getPosixSupport(), path.value); + context.getPosixSupport().chdir(path.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1874,10 +1834,9 @@ static PNone chdirPath(VirtualFrame frame, PosixPath path, static PNone chdirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.fchdir(context.getPosixSupport(), fd.fd); + context.getPosixSupport().fchdir(fd.fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); } @@ -1899,12 +1858,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone fchdir(VirtualFrame frame, int fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { while (true) { try { - posixLib.fchdir(context.getPosixSupport(), fd); + context.getPosixSupport().fchdir(fd); return PNone.NONE; } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -1931,11 +1889,10 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean isatty(int fd, @Cached GilNode gil, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { + @Bind PythonContext context) { gil.release(true); try { - return posixLib.isatty(context.getPosixSupport(), fd); + return context.getPosixSupport().isatty(fd); } finally { gil.acquire(); } @@ -1955,13 +1912,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PScandirIterator scandirPath(VirtualFrame frame, PosixPath path, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { - return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, posixLib.opendir(context.getPosixSupport(), path.value), path, false); + return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, context.getPosixSupport().opendir(path.value), path, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -1970,12 +1926,11 @@ static PScandirIterator scandirPath(VirtualFrame frame, PosixPath path, @Specialization static PScandirIterator scandirFd(VirtualFrame frame, PosixFd fd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, fd.originalObject); - Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); + Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, dirStream, fd, true); } } @@ -1994,13 +1949,14 @@ protected ArgumentClinicProvider getArgumentClinic() { static PList listdirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, + @Shared @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Shared @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { - return listdir(frame, inliningTarget, posixLib.opendir(context.getPosixSupport(), path.value), path.wasBufferLike, false, posixLib, constructAndRaiseNode, - context.getLanguage(inliningTarget), context.getPosixSupport()); + return listdir(frame, inliningTarget, context.getPosixSupport().opendir(path.value), path.wasBufferLike, false, constructAndRaiseNode, + context.getLanguage(inliningTarget), context.getPosixSupport(), opaquePathToBytesNode, getPathAsStringNode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); } @@ -2010,38 +1966,41 @@ static PList listdirPath(VirtualFrame frame, PosixPath path, static PList listdirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, + @Shared @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Shared @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, fd.originalObject); - Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); - return listdir(frame, inliningTarget, dirStream, false, true, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); + Object dirStream = dupAndFdopendir(frame, inliningTarget, context.getPosixSupport(), fd, constructAndRaiseNode); + return listdir(frame, inliningTarget, dirStream, false, true, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport(), opaquePathToBytesNode, + getPathAsStringNode); } - private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dirStream, boolean produceBytes, boolean needsRewind, PosixSupportLibrary posixLib, - PConstructAndRaiseNode.Lazy constructAndRaiseNode, PythonLanguage language, PosixSupport posixSupport) { + private static PList listdir(VirtualFrame frame, Node inliningTarget, Object dirStream, boolean produceBytes, boolean needsRewind, PConstructAndRaiseNode.Lazy constructAndRaiseNode, + PythonLanguage language, PosixSupport posixSupport, OpaquePathToBytesNode opaquePathToBytesNode, + PosixSupportNodes.GetPathAsStringNode getPathAsStringNode) { List list = new ArrayList<>(); try { while (true) { - Object dirEntry = posixLib.readdir(posixSupport, dirStream); + Object dirEntry = posixSupport.readdir(dirStream); if (dirEntry == null) { return PFactory.createList(language, listToArray(list)); } - Object name = posixLib.dirEntryGetName(posixSupport, dirEntry); + Object name = posixSupport.dirEntryGetName(dirEntry); if (produceBytes) { - addToList(list, opaquePathToBytes(name, posixLib, posixSupport, language)); + addToList(list, opaquePathToBytesNode.execute(inliningTarget, posixSupport, name, language)); } else { - addToList(list, posixLib.getPathAsString(posixSupport, name)); + addToList(list, getPathAsStringNode.execute(inliningTarget, posixSupport, name)); } } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { if (needsRewind) { - posixLib.rewinddir(posixSupport, dirStream); + posixSupport.rewinddir(dirStream); } try { - posixLib.closedir(posixSupport, dirStream); + posixSupport.closedir(dirStream); } catch (PosixException e) { // ignored (CPython does not check the return value of closedir) } @@ -2059,16 +2018,16 @@ private static Object[] listToArray(List list) { } } - static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupportLibrary posixLib, Object posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + static Object dupAndFdopendir(VirtualFrame frame, Node inliningTarget, PosixSupport posixSupport, PosixFd fd, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int dupFd = -1; try { - dupFd = posixLib.dup(posixSupport, fd.fd); + dupFd = posixSupport.dup(fd.fd); // when fdopenddir succeeds, we are no longer responsible for closing dupFd - return posixLib.fdopendir(posixSupport, dupFd); + return posixSupport.fdopendir(dupFd); } catch (PosixException e) { if (dupFd != -1) { try { - posixLib.close(posixSupport, dupFd); + posixSupport.close(dupFd); } catch (PosixException e1) { // ignored } @@ -2181,12 +2140,11 @@ static PNone utimensat(VirtualFrame frame, PosixPath path, Object times, Object @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.utimensat(context.getPosixSupport(), dirFd, path.value, timespec, followSymlinks); + context.getPosixSupport().utimensat(dirFd, path.value, timespec, followSymlinks); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2200,12 +2158,11 @@ static PNone utimes(VirtualFrame frame, PosixPath path, Object times, Object ns, @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.utimes(context.getPosixSupport(), path.value, timeval); + context.getPosixSupport().utimes(path.value, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2219,12 +2176,11 @@ static PNone lutimes(VirtualFrame frame, PosixPath path, Object times, Object ns @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.lutimes(context.getPosixSupport(), path.value, timeval); + context.getPosixSupport().lutimes(path.value, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2252,12 +2208,11 @@ static PNone futimens(VirtualFrame frame, PosixFd fd, Object times, Object ns, i @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.futimens(context.getPosixSupport(), fd.fd, timespec); + context.getPosixSupport().futimens(fd.fd, timespec); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2271,12 +2226,11 @@ static PNone futimes(VirtualFrame frame, PosixFd fd, Object times, Object ns, in @Shared @Cached UtimeArgsToTimespecNode timespecNode, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { - posixLib.futimes(context.getPosixSupport(), fd.fd, timeval); + context.getPosixSupport().futimes(fd.fd, timeval); } catch (PosixException e) { // filename is intentionally not included, see CPython's os_utime_impl throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -2319,13 +2273,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone rename(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RENAME, src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); try { - posixLib.renameat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value); + context.getPosixSupport().renameat(srcDirFd, src.value, dstDirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -2349,13 +2302,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static PNone replace(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDirFd, int dstDirFd, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_RENAME, src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); try { - posixLib.replaceat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value); + context.getPosixSupport().replaceat(srcDirFd, src.value, dstDirFd, dst.value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, src.originalObject, dst.originalObject); } @@ -2381,10 +2333,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static boolean access(PosixPath path, int mode, int dirFd, boolean effectiveIds, boolean followSymlinks, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.faccessat(context.getPosixSupport(), dirFd, path.value, mode, effectiveIds, followSymlinks); + return context.getPosixSupport().faccessat(dirFd, path.value, mode, effectiveIds, followSymlinks); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -2406,11 +2357,10 @@ static PNone fchmod(VirtualFrame frame, int fd, int mode, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHMOD, fd, mode, -1); try { - posixLib.fchmod(context.getPosixSupport(), fd, mode); + context.getPosixSupport().fchmod(fd, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd); } @@ -2436,12 +2386,11 @@ static PNone chmodFollow(VirtualFrame frame, PosixPath path, int mode, int dirFd @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHMOD, path.originalObject, mode, dirFdForAudit(dirFd)); try { - posixLib.fchmodat(context.getPosixSupport(), dirFd, path.value, mode, followSymlinks); + context.getPosixSupport().fchmodat(dirFd, path.value, mode, followSymlinks); } catch (PosixException e) { // TODO CPython checks for ENOTSUP as well if (e.hasErrno(OSErrorEnum.EOPNOTSUPP) && !followSymlinks) { @@ -2461,7 +2410,6 @@ static PNone chmodFollow(VirtualFrame frame, PosixFd fd, int mode, int dirFd, @S @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @SuppressWarnings("unused") @Shared @Cached PRaiseNode raiseNode) { @@ -2471,7 +2419,7 @@ static PNone chmodFollow(VirtualFrame frame, PosixFd fd, int mode, int dirFd, @S // arguments is used, CPython's implementation of chmod simply ignores dir_fd and // follow_symlinks if a fd is specified instead of a path. try { - posixLib.fchmod(context.getPosixSupport(), fd.fd, mode); + context.getPosixSupport().fchmod(fd.fd, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, fd.originalObject); } @@ -2490,14 +2438,13 @@ static Object chown(VirtualFrame frame, int fd, long uid, long gid, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHOWN, fd, uid, gid, -1); try { gil.release(true); try { - posixLib.fchown(context.getPosixSupport(), fd, uid, gid); + context.getPosixSupport().fchown(fd, uid, gid); } finally { gil.acquire(); } @@ -2524,14 +2471,13 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_OS_CHOWN, path.originalObject, uid, gid, -1); try { gil.release(true); try { - posixLib.fchownat(context.getPosixSupport(), AT_FDCWD.value, path.value, uid, gid, false); + context.getPosixSupport().fchownat(AT_FDCWD.value, path.value, uid, gid, false); } finally { gil.acquire(); } @@ -2560,7 +2506,6 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, int @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @@ -2569,7 +2514,7 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, int try { gil.release(true); try { - posixLib.fchownat(context.getPosixSupport(), dirFd, path.value, uid, gid, followSymlinks); + context.getPosixSupport().fchownat(dirFd, path.value, uid, gid, followSymlinks); } finally { gil.acquire(); } @@ -2584,7 +2529,6 @@ static Object chown(VirtualFrame frame, PosixFd fd, long uid, long gid, int dirF @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { @@ -2598,7 +2542,7 @@ static Object chown(VirtualFrame frame, PosixFd fd, long uid, long gid, int dirF try { gil.release(true); try { - posixLib.fchown(context.getPosixSupport(), fd.fd, uid, gid); + context.getPosixSupport().fchown(fd.fd, uid, gid); } finally { gil.acquire(); } @@ -2630,15 +2574,16 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object readlinkAsBytes(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile wasBufferLikeProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object link = posixLib.readlinkat(context.getPosixSupport(), dirFd, path.value); + Object link = context.getPosixSupport().readlinkat(dirFd, path.value); if (wasBufferLikeProfile.profile(inliningTarget, path.wasBufferLike)) { - return opaquePathToBytes(link, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), link, context.getLanguage(inliningTarget)); } else { - return posixLib.getPathAsString(context.getPosixSupport(), link); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), link); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject); @@ -2657,10 +2602,8 @@ protected ArgumentClinicProvider getArgumentClinic() { } @Specialization - static TruffleString getStrError(int code, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.strerror(context.getPosixSupport(), code); + static TruffleString getStrError(int code, @Bind PythonContext context) { + return context.getPosixSupport().strerror(code); } } @@ -2719,14 +2662,13 @@ static PTuple waitpid(VirtualFrame frame, long pid, int options, @Bind Node inliningTarget, @Cached GilNode gil, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { gil.release(true); try { while (true) { try { - long[] result = posixLib.waitpid(context.getPosixSupport(), pid, options); + long[] result = context.getPosixSupport().waitpid(inliningTarget, pid, options); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{result[0], result[1]}); } catch (PosixException e) { errorProfile.enter(inliningTarget); @@ -2750,28 +2692,27 @@ abstract static class WaitstatusToExitcodeNode extends PythonUnaryBuiltinNode { @Specialization static int waitstatusToExitcode(VirtualFrame frame, Object statusObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PyLongAsIntNode longAsInt, @Cached PRaiseNode raiseNode) { int status = longAsInt.execute(frame, inliningTarget, statusObj); PosixSupport posixSupport = context.getPosixSupport(); - if (posixLib.wifexited(posixSupport, status)) { - int exitcode = posixLib.wexitstatus(posixSupport, status); + if (posixSupport.wifexited(status)) { + int exitcode = posixSupport.wexitstatus(status); if (exitcode < 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WEXITSTATUS, exitcode); } return exitcode; } - if (posixLib.wifsignaled(posixSupport, status)) { - int signum = posixLib.wtermsig(posixSupport, status); + if (posixSupport.wifsignaled(status)) { + int signum = posixSupport.wtermsig(status); if (signum <= 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WTERMSIG, signum); } return -signum; } - if (posixLib.wifstopped(posixSupport, status)) { - int signum = posixLib.wstopsig(posixSupport, status); + if (posixSupport.wifstopped(status)) { + int signum = posixSupport.wstopsig(status); throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.PROCESS_STOPPED_BY_DELIVERY_OF_SIGNAL, signum); } throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.INVALID_WAIT_STATUS, status); @@ -2789,9 +2730,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wcoredump(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wcoredump(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wcoredump(status); } } @@ -2806,9 +2746,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifcontinued(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifcontinued(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifcontinued(status); } } @@ -2823,9 +2762,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifstopped(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifstopped(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifstopped(status); } } @@ -2840,9 +2778,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifsignaled(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifsignaled(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifsignaled(status); } } @@ -2857,9 +2794,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static boolean wifexited(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wifexited(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wifexited(status); } } @@ -2874,9 +2810,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static int wexitstatus(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wexitstatus(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wexitstatus(status); } } @@ -2891,9 +2826,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization int wtermsig(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wtermsig(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wtermsig(status); } } @@ -2908,9 +2842,8 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static int wstopsig(int status, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib) { - return posixLib.wstopsig(context.getPosixSupport(), status); + @Bind PythonContext context) { + return context.getPosixSupport().wstopsig(status); } } @@ -2927,23 +2860,23 @@ protected ArgumentClinicProvider getArgumentClinic() { static int system(VirtualFrame frame, Object command, @Bind Node inliningTarget, @Cached BytesNodes.ToBytesNode toBytesNode, + @Cached PosixSupportNodes.CreateWideStringFromStringNode createWideStringFromStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil) { // Unlike in other posix builtins, we go through str -> bytes -> byte[] -> String // conversions for emulated backend because the bytes version after fsencode conversion // is subject to sys.audit. auditNode.audit(frame, inliningTarget, T_OS_SYSTEM, command); + Object cmdOpaque; + if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { + cmdOpaque = createWideStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), (TruffleString) command); + } else { + cmdOpaque = context.getPosixSupport().createCStringFromBytes(toBytesNode.execute((PBytes) command)); + } gil.release(true); try { - Object cmdOpaque; - if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { - cmdOpaque = posixLib.createWideStringFromString(context.getPosixSupport(), (TruffleString) command); - } else { - cmdOpaque = posixLib.createCStringFromBytes(context.getPosixSupport(), toBytesNode.execute((PBytes) command)); - } - return posixLib.system(context.getPosixSupport(), cmdOpaque); + return context.getPosixSupport().system(cmdOpaque); } finally { gil.acquire(); } @@ -3010,7 +2943,6 @@ static long sysconf(VirtualFrame frame, PythonModule self, Object arg, @Cached PyObjectGetItem getItem, @Cached PRaiseNode raiseNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int id; if (longCheckNode.execute(inliningTarget, arg)) { @@ -3027,7 +2959,7 @@ static long sysconf(VirtualFrame frame, PythonModule self, Object arg, throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.CONFIGURATION_NAMES_MUST_BE_STRINGS_OR_INTEGERS); } try { - return posixLib.sysconf(context.getPosixSupport(), id); + return context.getPosixSupport().sysconf(id); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -3048,10 +2980,9 @@ protected ArgumentClinicProvider getArgumentClinic() { static int umask(VirtualFrame frame, int mask, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.umask(context.getPosixSupport(), mask); + return context.getPosixSupport().umask(mask); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -3065,10 +2996,11 @@ abstract static class CtermId extends PythonBuiltinNode { static TruffleString ctermid(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, + @Cached DecodeFilesystemStringNode decodeNode) { try { - return posixLib.ctermid(context.getPosixSupport()); + Object result = context.getPosixSupport().ctermid(); + return decodeNode.execute(inliningTarget, context.getPosixSupport(), result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -3090,11 +3022,10 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_KILL, pid, signal); try { - posixLib.kill(context.getPosixSupport(), pid, signal); + context.getPosixSupport().kill(pid, signal); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -3117,11 +3048,10 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_KILLPG, pid, signal); try { - posixLib.killpg(context.getPosixSupport(), pid, signal); + context.getPosixSupport().killpg(pid, signal); return PNone.NONE; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -3157,7 +3087,7 @@ static Object register(Object before, Object afterInChild, Object afterInParent) /** * Helper node that accepts either str or bytes and converts it to a representation specific to - * the {@link PosixSupportLibrary} in use. Basically equivalent of + * the {@link PosixSupport} in use. Basically equivalent of * {@code PyUnicode_EncodeFSDefault}. */ @GenerateInline @@ -3169,20 +3099,20 @@ abstract static class StringOrBytesToOpaquePathNode extends Node { @Specialization(guards = "isString(strObj)") static Object doString(Node inliningTarget, Object strObj, @Cached CastToTruffleStringNode castToStringNode, + @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, strObj); - return checkPath(inliningTarget, posixLib.createPathFromString(context.getPosixSupport(), str), raiseNode); + return checkPath(inliningTarget, createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), str), raiseNode); } @Specialization static Object doBytes(Node inliningTarget, PBytes bytes, @Cached(inline = false) BytesNodes.ToBytesNode toBytesNode, + @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { - return checkPath(inliningTarget, posixLib.createPathFromBytes(context.getPosixSupport(), toBytesNode.execute(bytes)), raiseNode); + return checkPath(inliningTarget, createPathFromBytesNode.execute(inliningTarget, context.getPosixSupport(), toBytesNode.execute(bytes)), raiseNode); } private static Object checkPath(Node inliningTarget, Object path, PRaiseNode raiseNode) { @@ -3195,7 +3125,7 @@ private static Object checkPath(Node inliningTarget, Object path, PRaiseNode rai /** * Similar to {@code PyUnicode_FSConverter}, but the actual conversion is delegated to the - * {@link PosixSupportLibrary} implementation. + * {@link PosixSupport} implementation. */ @GenerateInline @GenerateCached(false) @@ -3364,14 +3294,22 @@ private static BigInteger convertToNanoseconds(long sec, long ns) { return r.add(BigInteger.valueOf(ns)); } - public static PBytes opaquePathToBytes(Object opaquePath, PosixSupportLibrary posixLib, Object posixSupport, PythonLanguage language) { - Buffer buf = posixLib.getPathAsBytes(posixSupport, opaquePath); - if (buf.length > Integer.MAX_VALUE) { - // sanity check that it is safe to cast result.length to int, to be removed once - // we support large arrays - throw CompilerDirectives.shouldNotReachHere("Posix path cannot fit into a Java array"); + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class OpaquePathToBytesNode extends PNodeWithContext { + public abstract PBytes execute(Node inliningTarget, PosixSupport posixSupport, Object opaquePath, PythonLanguage language); + + @Specialization + static PBytes doConvert(Node inliningTarget, PosixSupport posixSupport, Object opaquePath, PythonLanguage language, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode) { + Buffer buf = getPathAsBytesNode.execute(inliningTarget, posixSupport, opaquePath); + if (buf.length > Integer.MAX_VALUE) { + // sanity check that it is safe to cast result.length to int, to be removed once + // we support large arrays + throw CompilerDirectives.shouldNotReachHere("Posix path cannot fit into a Java array"); + } + return PFactory.createBytes(language, buf.data, (int) buf.length); } - return PFactory.createBytes(language, buf.data, (int) buf.length); } // ------------------ @@ -3511,12 +3449,13 @@ public PathConversionNode(String functionName, String argumentName, boolean null } @Specialization(guards = "nullable") + @SuppressWarnings("truffle-static-method") // checkPath uses this node's error-message metadata. PosixFileHandle doNone(@SuppressWarnings("unused") PNone value, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = posixLib.createPathFromString(context.getPosixSupport(), T_DOT); + Object path = createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), T_DOT); return new PosixPath(null, checkPath(inliningTarget, path, raiseNode), false); } @@ -3553,10 +3492,10 @@ PosixFileHandle doUnicode(Object value, @Bind Node inliningTarget, @Exclusive @Cached CastToTruffleStringNode castToStringNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Exclusive @Cached PRaiseNode raiseNode) { TruffleString str = castToStringNode.execute(inliningTarget, value); - Object path = posixLib.createPathFromString(context.getPosixSupport(), str); + Object path = createPathFromStringNode.execute(null, inliningTarget, context.getPosixSupport(), str); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), false); } @@ -3566,9 +3505,9 @@ PosixFileHandle doBytes(PBytes value, @Bind Node inliningTarget, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Exclusive @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Exclusive @Cached PRaiseNode raiseNode) { - Object path = posixLib.createPathFromBytes(context.getPosixSupport(), toByteArrayNode.execute(value)); + Object path = createPathFromBytesNode.execute(inliningTarget, context.getPosixSupport(), toByteArrayNode.execute(value)); return new PosixPath(value, checkPath(inliningTarget, path, raiseNode), true); } @@ -3592,8 +3531,9 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, @Cached("create(T___FSPATH__)") LookupAndCallUnaryNode callFSPath, @Exclusive @Cached BytesNodes.ToBytesNode toByteArrayNode, @Exclusive @Cached CastToTruffleStringNode castToStringNode, + @Exclusive @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, + @Exclusive @Cached PosixSupportNodes.CreatePathFromBytesNode createPathFromBytesNode, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { Object pathObject; try { @@ -3605,10 +3545,10 @@ PosixFileHandle doGeneric(VirtualFrame frame, Object value, // 'pathObject' replaces 'value' as the PosixPath.originalObject for auditing purposes // by design if (pathObject instanceof PBytes) { - return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, posixLib, raiseNode); + return doBytes((PBytes) pathObject, inliningTarget, toByteArrayNode, context, createPathFromBytesNode, raiseNode); } if (PGuards.isString(pathObject)) { - return doUnicode(pathObject, inliningTarget, castToStringNode, context, posixLib, raiseNode); + return doUnicode(pathObject, inliningTarget, castToStringNode, context, createPathFromStringNode, raiseNode); } throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.EXPECTED_FSPATH_TO_RETURN_STR_OR_BYTES, value, pathObject); } @@ -3825,11 +3765,11 @@ protected PosixFileHandle(Object originalObject) { } /** - * Contains the path converted to the representation used by the {@code PosixSupportLibrary} + * Contains the path converted to the representation used by the {@code PosixSupport} * implementation * - * @see PosixSupportLibrary#createPathFromString(Object, TruffleString) - * @see PosixSupportLibrary#createPathFromBytes(Object, byte[]) + * @See PosixSupportNodes#CreatePathFromStringNode + * @See PosixSupportNodes#CreatePathFromBytesNode */ public static class PosixPath extends PosixFileHandle { public final Object value; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java index e5e4fae2e9..d95c6f9a8e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java @@ -53,8 +53,8 @@ import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -62,7 +62,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -90,11 +89,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static int shmOpen(VirtualFrame frame, TruffleString path, int flags, int mode, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); - return posixLib.shmOpen(context.getPosixSupport(), name, flags, mode); + Object name = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), path); + return context.getPosixSupport().shmOpen(name, flags, mode); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); } @@ -115,11 +114,11 @@ protected ArgumentClinicProvider getArgumentClinic() { static PNone shmUnlink(VirtualFrame frame, TruffleString path, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - Object name = posixLib.createCStringFromString(context.getPosixSupport(), path); - posixLib.shmUnlink(context.getPosixSupport(), name); + Object name = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), path); + context.getPosixSupport().shmUnlink(name); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java index 22b17b9833..b3f45dee0f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java @@ -81,9 +81,9 @@ import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -97,7 +97,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -110,7 +110,7 @@ protected List> getNodeFa /** * Helper converter which iterates the argv argument and converts each element to the opaque - * narrow string representation used by {@link PosixSupportLibrary}. + * narrow string representation used by {@link PosixSupport}. */ abstract static class ProcessArgsConversionNode extends ArgumentCastNode { @Specialization @@ -128,7 +128,7 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, @Cached GetSequenceStorageNode getSequenceStorageNode, @Cached IsBuiltinObjectProfile isBuiltinClassProfile, @Cached ObjectToOpaquePathNode objectToOpaquePathNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, @Cached("createNotNormalized()") GetItemNode getItemNode, @Cached PRaiseNode raiseNode) { PList argsList; @@ -150,9 +150,10 @@ static Object[] doSequence(VirtualFrame frame, Object processArgs, } Object o = getItemNode.execute(argsStorage, i); Object path = objectToOpaquePathNode.execute(frame, inliningTarget, o, false); - Buffer bytes = posixLib.getPathAsBytes(context.getPosixSupport(), path); - argsArray[i] = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes.data); + Buffer bytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), path); + argsArray[i] = context.getPosixSupport().createCStringFromBytes(bytes.data); } + LoopNode.reportLoopCount(inliningTarget, len); return argsArray; } @@ -176,7 +177,6 @@ static Object doSequence(VirtualFrame frame, Object env, @Cached PyObjectSizeNode sizeNode, @Cached ToBytesNode toBytesNode, @Cached PyObjectGetItem getItem, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode) { // TODO unlike CPython, this accepts a dict (if the keys are integers (0, 1, ..., len-1) int length = sizeNode.execute(frame, inliningTarget, env); @@ -184,12 +184,13 @@ static Object doSequence(VirtualFrame frame, Object env, for (int i = 0; i < length; ++i) { Object o = getItem.execute(frame, inliningTarget, env, i); byte[] bytes = toBytesNode.execute(frame, o); - Object o1 = posixLib.createCStringFromBytes(context.getPosixSupport(), bytes); + Object o1 = context.getPosixSupport().createCStringFromBytes(bytes); if (o1 == null) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.EMBEDDED_NULL_BYTE); } result[i] = o1; } + LoopNode.reportLoopCount(inliningTarget, length); return result; } @@ -236,11 +237,11 @@ private static byte[] fsEncode(String s) { return s.getBytes(); } - private static Object createCStringFromBytes(Node inliningTarget, byte[] bytes, PosixSupportLibrary posixLib, PRaiseNode raiseNode) { - Object o = posixLib.createCStringFromBytes(PosixSupport.get(inliningTarget), bytes); + private static Object createCStringFromBytes(Node inliningTarget, byte[] bytes, PRaiseNode raiseNode) { + Object o = PosixSupport.get(inliningTarget).createCStringFromBytes(bytes); if (o == null) { - // TODO reconsider the contract of PosixSupportLibrary#createCStringFromBytes w.r.t. - // embedded null checks (we need to review that anyway since PosixSupportLibrary + // TODO reconsider the contract of PosixSupport#createCStringFromBytes w.r.t. + // embedded null checks (we need to review that anyway since PosixSupport // cannot do Python-specific fsencode) throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.EMBEDDED_NULL_BYTE); } @@ -255,7 +256,6 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo int stderrRead, int stderrWrite, int errPipeRead, int errPipeWrite, boolean restoreSignals, boolean callSetsid, int pgidToSet, Object gidObject, Object groupsList, Object uidObject, int childUmask, Object preexecFn, boolean allowVFork, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createNotNormalized()") GetItemNode tupleGetItem, @Cached TupleNodes.GetTupleStorage getTupleStorage, @@ -296,7 +296,7 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo } Object[] extendedArgs = new Object[additionalArgs.length + (processArgs.length == 0 ? 0 : processArgs.length - 1)]; for (int j = 0; j < additionalArgs.length; ++j) { - extendedArgs[j] = createCStringFromBytes(inliningTarget, fsEncode(additionalArgs[j].toJavaStringUncached()), posixLib, raiseNode); + extendedArgs[j] = createCStringFromBytes(inliningTarget, fsEncode(additionalArgs[j].toJavaStringUncached()), raiseNode); } if (processArgs.length > 1) { PythonUtils.arraycopy(processArgs, 1, extendedArgs, additionalArgs.length, processArgs.length - 1); @@ -304,13 +304,14 @@ static int forkExec(VirtualFrame frame, Object[] args, Object executableList, bo processArgs = extendedArgs; executables[i] = extendedArgs[0]; } else { - executables[i] = createCStringFromBytes(inliningTarget, bytes, posixLib, raiseNode); + executables[i] = createCStringFromBytes(inliningTarget, bytes, raiseNode); } } + LoopNode.reportLoopCount(inliningTarget, length); gil.release(true); try { - return posixLib.forkExec(context.getPosixSupport(), executables, processArgs, cwd, env == null ? null : (Object[]) env, stdinRead, stdinWrite, stdoutRead, stdoutWrite, stderrRead, + return context.getPosixSupport().forkExec(executables, processArgs, cwd, env == null ? null : (Object[]) env, stdinRead, stdinWrite, stdoutRead, stdoutWrite, stderrRead, stderrWrite, errPipeRead, errPipeWrite, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); } catch (PosixException e) { gil.acquire(); @@ -343,6 +344,7 @@ private static int[] convertFdSequence(Node inliningTarget, SequenceStorage stor } throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BAD_VALUES_IN_FDS_TO_KEEP); } + LoopNode.reportLoopCount(inliningTarget, len); return fds; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java index b05f6a58d5..5633aec2b3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PwdModuleBuiltins.java @@ -70,21 +70,29 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; +import com.oracle.graal.python.nodes.util.PosixSupportNodes.DecodeFilesystemStringNode; +import com.oracle.graal.python.runtime.EmulatedPosixSupport.EmulatedPwdResult; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; +import com.oracle.graal.python.runtime.NativePosixSupport.NativePwdResult; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PwdResult; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.GenerateCached; +import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -105,8 +113,7 @@ public final class PwdModuleBuiltins extends PythonBuiltins { @Override protected List> getNodeFactories() { - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); - boolean hasGetpwentries = posixLib.hasGetpwentries(PythonContext.get(null).getPosixSupport()); + boolean hasGetpwentries = PythonContext.get(null).getPosixSupport().hasGetpwentries(); if (hasGetpwentries) { return PwdModuleBuiltinsFactory.getFactories(); } else { @@ -122,16 +129,49 @@ public void initialize(Python3Core core) { StructSequence.initType(core, STRUCT_PASSWD_DESC); } - private static Object[] createPwuidObject(Node inliningTarget, PwdResult pwd, PythonLanguage language, InlinedConditionProfile unsignedConversionProfile) { - return new Object[]{ - pwd.name, - T_NOT_AVAILABLE, - PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, pwd.uid), - PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, pwd.gid), - /* gecos: */ T_EMPTY_STRING, - pwd.dir, - pwd.shell - }; + @GenerateUncached + @GenerateInline + @GenerateCached(false) + public abstract static class PwdResultToStructSeqNode extends com.oracle.graal.python.nodes.PNodeWithContext { + public abstract Object[] execute(Node inliningTarget, PosixSupport posixSupport, PwdResult pwd); + + @Specialization + static Object[] doNative(Node inliningTarget, PosixSupport posixSupport, NativePwdResult pwd, + @Bind PythonLanguage language, + @Exclusive @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached DecodeFilesystemStringNode decodeNameNode, + @Cached DecodeFilesystemStringNode decodeDirNode, + @Cached DecodeFilesystemStringNode decodeShellNode) { + return createObject(inliningTarget, language, unsignedConversionProfile, + decodeNameNode.execute(inliningTarget, posixSupport, pwd.name), + pwd.uid, pwd.gid, + decodeDirNode.execute(inliningTarget, posixSupport, pwd.dir), + decodeShellNode.execute(inliningTarget, posixSupport, pwd.shell)); + } + + @Specialization + static Object[] doEmulated(@SuppressWarnings("unused") Node inliningTarget, @SuppressWarnings("unused") PosixSupport posixSupport, EmulatedPwdResult pwd, + @Bind PythonLanguage language, + @Exclusive @Cached InlinedConditionProfile unsignedConversionProfile) { + return createObject(inliningTarget, language, unsignedConversionProfile, + TruffleString.fromJavaStringUncached(pwd.name, com.oracle.graal.python.util.PythonUtils.TS_ENCODING), + pwd.uid, pwd.gid, + TruffleString.fromJavaStringUncached(pwd.dir, com.oracle.graal.python.util.PythonUtils.TS_ENCODING), + TruffleString.fromJavaStringUncached(pwd.shell, com.oracle.graal.python.util.PythonUtils.TS_ENCODING)); + } + + private static Object[] createObject(Node inliningTarget, PythonLanguage language, InlinedConditionProfile unsignedConversionProfile, + TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { + return new Object[]{ + name, + T_NOT_AVAILABLE, + PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, uid), + PInt.createPythonIntFromUnsignedLong(inliningTarget, language, unsignedConversionProfile, gid), + /* gecos: */ T_EMPTY_STRING, + dir, + shell + }; + } } @Builtin(name = "getpwuid", minNumOfPositionalArgs = 1, parameterNames = {"uid"}) @@ -144,8 +184,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, @Cached UidConversionNode uidConversionNode, @Cached IsBuiltinObjectProfile classProfile, @Cached GilNode gil, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { long uid; @@ -161,7 +200,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, try { gil.release(true); try { - pwd = posixLib.getpwuid(context.getPosixSupport(), uid); + pwd = context.getPosixSupport().getpwuid(uid); } finally { gil.acquire(context); } @@ -172,7 +211,7 @@ static Object doGetpwuid(VirtualFrame frame, Object uidObj, throw raiseUidNotFound(inliningTarget, raiseNode); } PythonLanguage language = context.getLanguage(inliningTarget); - return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, pwd, language, unsignedConversionProfile)); + return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, resultNode.execute(inliningTarget, context.getPosixSupport(), pwd)); } private static PException raiseUidNotFound(Node inliningTarget, PRaiseNode raiseNode) { @@ -196,21 +235,21 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, @Bind PythonContext context, @Cached GilNode gil, @Cached StringOrBytesToOpaquePathNode encodeFSDefault, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PosixSupportNodes.GetPathAsBytesNode getPathAsBytesNode, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language, @Cached PRaiseNode raiseNode) { // Note: CPython also takes only Strings, not bytes, and then encodes the String // StringOrBytesToOpaquePathNode already checks for embedded '\0' Object pathEncoded = encodeFSDefault.execute(inliningTarget, name); - Buffer nameBytes = posixLib.getPathAsBytes(context.getPosixSupport(), pathEncoded); - Object nameEncoded = posixLib.createCStringFromBytes(context.getPosixSupport(), nameBytes.data); + Buffer nameBytes = getPathAsBytesNode.execute(inliningTarget, context.getPosixSupport(), pathEncoded); + Object nameEncoded = context.getPosixSupport().createCStringFromBytes(nameBytes.data); PwdResult pwd; try { gil.release(true); try { - pwd = posixLib.getpwnam(context.getPosixSupport(), nameEncoded); + pwd = context.getPosixSupport().getpwnam(nameEncoded); } finally { gil.acquire(context); } @@ -220,7 +259,7 @@ static Object doGetpwname(VirtualFrame frame, TruffleString name, if (pwd == null) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.KeyError, ErrorMessages.GETPWNAM_NAME_NOT_FOUND, name); } - return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, pwd, context.getLanguage(inliningTarget), unsignedConversionProfile)); + return PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, resultNode.execute(inliningTarget, context.getPosixSupport(), pwd)); } } @@ -231,21 +270,22 @@ public abstract static class GetpwallNode extends PythonBuiltinNode { static Object doGetpall(VirtualFrame frame, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @Cached InlinedConditionProfile unsignedConversionProfile, + @Cached PwdResultToStructSeqNode resultNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // We cannot release the GIL, because the underlying POSIX calls are not thread safe PwdResult[] entries; try { - entries = posixLib.getpwentries(context.getPosixSupport()); + entries = context.getPosixSupport().getpwentries(); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } PythonLanguage language = context.getLanguage(inliningTarget); Object[] result = new Object[entries.length]; for (int i = 0; i < result.length; i++) { - result[i] = PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, createPwuidObject(inliningTarget, entries[i], language, unsignedConversionProfile)); + result[i] = PFactory.createStructSeq(language, STRUCT_PASSWD_DESC, + resultNode.execute(inliningTarget, context.getPosixSupport(), entries[i])); } + LoopNode.reportLoopCount(inliningTarget, result.length); return PFactory.createList(language, result); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java index 59f59a6a52..a4370602c3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ResourceModuleBuiltins.java @@ -60,9 +60,8 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RusageResult; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; @@ -72,7 +71,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(defineModule = "resource") @@ -155,13 +153,12 @@ abstract static class GetRuUsageNode extends PythonBuiltinNode { static PTuple getruusage(VirtualFrame frame, int who, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { PosixSupport posixSupport = context.getPosixSupport(); RusageResult rusage; try { - rusage = posixLib.getrusage(posixSupport, who); + rusage = posixSupport.getrusage(who); } catch (PosixException e) { if (e.hasErrno(OSErrorEnum.EINVAL)) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.RUSAGE_INVALID_WHO); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java index 96b5e9ea1a..183fc6640a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SSLModuleBuiltins.java @@ -433,9 +433,8 @@ Object decode(VirtualFrame frame, Object path, @Bind Node inliningTarget, @Cached PyUnicodeFSDecoderNode asPath, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - return decode(inliningTarget, constructAndRaiseNode, toTruffleFile(frame, inliningTarget, asPath, path, toJavaStringNode, eqNode, constructAndRaiseNode)); + return decode(inliningTarget, constructAndRaiseNode, toTruffleFile(frame, inliningTarget, asPath, path, toJavaStringNode, constructAndRaiseNode)); } // No BoundaryCallContext: constructs and raises only builtin errors @@ -459,7 +458,7 @@ private Object decode(Node inliningTarget, PConstructAndRaiseNode.Lazy construct } private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUnicodeFSDecoderNode asPath, Object fileObject, TruffleString.ToJavaStringNode toJavaStringNode, - TruffleString.EqualNode eqNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { + PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { TruffleFile file; try { file = getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(asPath.execute(frame, fileObject))); @@ -468,7 +467,7 @@ private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUni } return file; } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java index 6f9963e03d..9a621b1fe4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SelectModuleBuiltins.java @@ -72,11 +72,10 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.ChannelNotSelectableException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PythonErrorType; import com.oracle.graal.python.runtime.object.PFactory; @@ -91,7 +90,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -134,7 +133,6 @@ abstract static class SelectNode extends PythonBuiltinNode { static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object xlist, Object timeout, @Bind Node inliningTarget, @Cached InlinedBranchProfile isNotNoneTimeout, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached PyObjectSizeNode sizeNode, @Cached PyObjectGetItem callGetItemNode, @Cached FastConstructListNode constructListNode, @@ -166,7 +164,7 @@ static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object x try { gil.release(true); try { - result = posixLib.select(PosixSupport.get(inliningTarget), readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval); + result = PosixSupport.get(inliningTarget).select(readFDs.fds, writeFDs.fds, xFDs.fds, timeoutval); } finally { gil.acquire(); } @@ -194,15 +192,15 @@ static PTuple doGeneric(VirtualFrame frame, Object rlist, Object wlist, Object x } } return PFactory.createTuple(language, new PList[]{ - toList(result.getReadFds(), readFDs, language), - toList(result.getWriteFds(), writeFDs, language), - toList(result.getErrorFds(), xFDs, language)}); + toList(inliningTarget, result.getReadFds(), readFDs, language), + toList(inliningTarget, result.getWriteFds(), writeFDs, language), + toList(inliningTarget, result.getErrorFds(), xFDs, language)}); } /** * Also maps the returned FDs back to their original Python level objects. */ - private static PList toList(boolean[] result, ObjAndFDList fds, PythonLanguage language) { + private static PList toList(Node inliningTarget, boolean[] result, ObjAndFDList fds, PythonLanguage language) { Object[] resultObjs = new Object[result.length]; int resultObjsIdx = 0; for (int i = 0; i < fds.fds.length; i++) { @@ -210,6 +208,7 @@ private static PList toList(boolean[] result, ObjAndFDList fds, PythonLanguage l resultObjs[resultObjsIdx++] = fds.objects[i]; } } + LoopNode.reportLoopCount(inliningTarget, fds.fds.length); return PFactory.createList(language, PythonUtils.arrayCopyOf(resultObjs, resultObjsIdx)); } @@ -231,6 +230,7 @@ private static ObjAndFDList seq2set(VirtualFrame frame, Node inliningTarget, Obj } fds.add(fd); } + LoopNode.reportLoopCount(inliningTarget, objects.size()); return new ObjAndFDList(objects.toArray(new Object[0]), fds.toArray()); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java index 16dad2ca2a..1d4a767c20 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java @@ -82,10 +82,9 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -99,7 +98,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -173,7 +171,7 @@ public void postInitialize(Python3Core core) { } var context = core.getContext(); - if (PosixSupportLibrary.getUncached().getBackend(context.getPosixSupport()).equalsUncached(T_JAVA, TS_ENCODING)) { + if (context.getPosixSupport().getBackend().equalsUncached(T_JAVA, TS_ENCODING)) { for (EmulatedSignal signal : EmulatedSignal.values()) { if (signalModule.getAttribute(signal.name) == PNone.NO_VALUE) { moduleData.signals.put(signal.name(), signal.number); @@ -298,10 +296,9 @@ abstract static class AlarmNode extends PythonUnaryClinicBuiltinNode { static int alarm(VirtualFrame frame, int seconds, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.alarm(context.getPosixSupport(), seconds); + return context.getPosixSupport().alarm(seconds); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -474,10 +471,9 @@ abstract static class RaiseSignalNode extends PythonUnaryClinicBuiltinNode { static PNone doInt(VirtualFrame frame, int signum, @Bind PythonContext context, @Bind Node inliningTarget, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.raise(context.getPosixSupport(), signum); + context.getPosixSupport().raise(signum); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -504,14 +500,13 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object doIt(VirtualFrame frame, int which, Object seconds, Object interval, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PyTimeFromObjectNode timeFromObjectNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { Timeval delay = toTimeval(frame, inliningTarget, seconds, timeFromObjectNode); Timeval intervalTimeval = toTimeval(frame, inliningTarget, interval, timeFromObjectNode); try { - return createResultTuple(language, posixLib.setitimer(context.getPosixSupport(), which, delay, intervalTimeval)); + return createResultTuple(language, context.getPosixSupport().setitimer(which, delay, intervalTimeval)); } catch (PosixException e) { throw raiseItimerError(frame, inliningTarget, e, constructAndRaiseNode); } @@ -556,11 +551,10 @@ protected ArgumentClinicProvider getArgumentClinic() { static Object doIt(VirtualFrame frame, int which, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { try { - return SetitimerNode.createResultTuple(language, posixLib.getitimer(context.getPosixSupport(), which)); + return SetitimerNode.createResultTuple(language, context.getPosixSupport().getitimer(which)); } catch (PosixException e) { throw SetitimerNode.raiseItimerError(frame, inliningTarget, e, constructAndRaiseNode); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index e838baaaf2..1d1c13f7fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -105,19 +105,17 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage; @@ -135,6 +133,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.memory.ByteArraySupport; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedExactClassProfile; @@ -200,7 +199,7 @@ public void postInitialize(Python3Core core) { PythonModule module = core.lookupBuiltinModule(T__SOCKET); module.setModuleState(-1L); if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 || - PosixSupportLibrary.getUncached().getBackend(core.getContext().getPosixSupport()).toJavaStringUncached().equals("java")) { + core.getContext().getPosixSupport().getBackend().toJavaStringUncached().equals("java")) { module.setAttribute(toTruffleStringUncached(PosixConstants.AF_UNIX.name), PNone.NO_VALUE); } } @@ -246,19 +245,21 @@ public abstract static class GetHostnameNode extends PythonBuiltinNode { @Specialization static TruffleString doGeneric(VirtualFrame frame, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTNAME); try { + Object hostname; gil.release(true); try { - return posixLib.getCStringAsString(context.getPosixSupport(), posixLib.gethostname(context.getPosixSupport())); + hostname = context.getPosixSupport().gethostname(); } finally { gil.acquire(); } + return getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), hostname); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -271,14 +272,13 @@ public abstract static class GetHostByAddrNode extends PythonUnaryBuiltinNode { @Specialization static Object doGeneric(VirtualFrame frame, Object ip, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached SocketNodes.MakeIpAddrNode makeIpAddrNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil) { @@ -288,29 +288,31 @@ static Object doGeneric(VirtualFrame frame, Object ip, */ auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYADDR, ip); UniversalSockAddr addr = setIpAddrNode.execute(frame, idnaConverter.execute(frame, ip), AF_UNSPEC.value); - int family = sockAddrLibrary.getFamily(addr); + int family = addr.getFamily(); try { - Object[] getnameinfoResult = posixLib.getnameinfo(context.getPosixSupport(), addr, NI_NAMEREQD.value); - TruffleString hostname = posixLib.getCStringAsString(context.getPosixSupport(), getnameinfoResult[0]); + Object[] getnameinfoResult = context.getPosixSupport().getnameinfo(addr, NI_NAMEREQD.value); + TruffleString hostname = getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), getnameinfoResult[0]); SequenceStorage storage = new ObjectSequenceStorage(5); try { AddrInfoCursor cursor; + Object zero = createCStringFromStringNode.execute(inliningTarget, context.getPosixSupport(), T_ZERO); gil.release(true); try { - cursor = posixLib.getaddrinfo(context.getPosixSupport(), getnameinfoResult[0], posixLib.createCStringFromString(context.getPosixSupport(), T_ZERO), + cursor = context.getPosixSupport().getaddrinfo(getnameinfoResult[0], zero, family, 0, 0, 0); } finally { gil.acquire(); } try { do { - UniversalSockAddr forwardAddr = addrInfoCursorLib.getSockAddr(cursor); + UniversalSockAddr forwardAddr = cursor.getSockAddr(); storage = appendNode.execute(inliningTarget, storage, makeIpAddrNode.execute(frame, inliningTarget, forwardAddr), SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); - } while (addrInfoCursorLib.next(cursor)); + } while (cursor.next()); + LoopNode.reportLoopCount(inliningTarget, storage.length()); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e1) { // Ignore failing forward lookup and return at least the hostname @@ -337,19 +339,18 @@ public abstract static class GetHostByNameNode extends PythonUnaryBuiltinNode { @Specialization static TruffleString getHostByName(VirtualFrame frame, Object nameObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYNAME, PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); try { - return posixLib.getCStringAsString(context.getPosixSupport(), posixLib.inet_ntop(context.getPosixSupport(), AF_INET.value, inet4SockAddr.getAddressAsBytes())); + return getCStringAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -367,12 +368,10 @@ public abstract static class GetHostByNameExNode extends PythonUnaryBuiltinNode @Specialization static Object get(VirtualFrame frame, Object nameObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, @Bind Node inliningTarget, @Cached("createIdnaConverter()") IdnaFromStringOrBytesConverterNode idnaConverter, @Cached SysModuleBuiltins.AuditNode auditNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); // The event name is really without the _ex, it's not a copy-paste error @@ -384,19 +383,19 @@ static Object get(VirtualFrame frame, Object nameObj, */ try { PosixSupport posixSupport = context.getPosixSupport(); - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromBytes(posixSupport, name), + AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromBytes(name), null, AF_INET.value, 0, 0, AI_CANONNAME.value); try { - TruffleString canonName = posixLib.getCStringAsString(posixSupport, addrInfoCursorLib.getCanonName(cursor)); - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addrInfoCursorLib.getSockAddr(cursor)); - TruffleString addr = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, AF_INET.value, inet4SockAddr.getAddressAsBytes())); + TruffleString canonName = getCStringAsStringNode.execute(inliningTarget, posixSupport, cursor.getCanonName()); + Inet4SockAddr inet4SockAddr = cursor.getSockAddr().asInet4SockAddr(); + TruffleString addr = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(AF_INET.value, inet4SockAddr.getAddressAsBytes())); // getaddrinfo doesn't support aliases PList aliases = PFactory.createList(context.getLanguage(inliningTarget)); // we support just one address for now PList addrs = PFactory.createList(context.getLanguage(inliningTarget), new Object[]{addr}); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{canonName, aliases, addrs}); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e) { throw constructAndRaiseNode.get(inliningTarget).executeWithArgsOnly(frame, SocketGAIError, new Object[]{e.getErrorCode(), e.getMessageAsTruffleString()}); @@ -421,12 +420,10 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec @Bind Node inliningTarget, @Cached InlinedConditionProfile noneProtocol, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached TruffleString.ToJavaStringNode toJavaStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { TruffleString protocolName; @@ -449,19 +446,20 @@ static Object getServByName(VirtualFrame frame, TruffleString serviceName, Objec } try { + PosixSupport posixSupport = context.getPosixSupport(); + Object service = createCStringFromStringNode.execute(inliningTarget, posixSupport, serviceName); gil.release(true); AddrInfoCursor cursor; try { - PosixSupport posixSupport = context.getPosixSupport(); - cursor = posixLib.getaddrinfo(posixSupport, null, posixLib.createCStringFromString(posixSupport, serviceName), AF_INET.value, 0, protocol, 0); + cursor = posixSupport.getaddrinfo(null, service, AF_INET.value, 0, protocol, 0); } finally { gil.acquire(); } try { - UniversalSockAddr addr = addrInfoCursorLib.getSockAddr(cursor); - return sockAddrLibrary.asInet4SockAddr(addr).getPort(); + UniversalSockAddr addr = cursor.getSockAddr(); + return addr.asInet4SockAddr().getPort(); } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); @@ -488,10 +486,10 @@ public abstract static class GetServByPortNode extends PythonBinaryClinicBuiltin Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, @Bind Node inliningTarget, @Cached InlinedConditionProfile nonProtocol, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached TruffleString.EqualNode equalNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { TruffleString protocolName; @@ -512,20 +510,21 @@ Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, auditNode.audit(frame, inliningTarget, T_SOCKET_GETSERVBYPORT, port, protocolName != null ? protocolName : T_EMPTY_STRING); try { + Object[] result; gil.release(true); try { - UniversalSockAddr addr = posixLib.createUniversalSockAddrInet4(getPosixSupport(), new Inet4SockAddr(port, INADDR_ANY.value)); + UniversalSockAddr addr = getPosixSupport().createUniversalSockAddrInet4(new Inet4SockAddr(port, INADDR_ANY.value)); int flags = 0; if (protocolName != null && equalNode.execute(protocolName, T_UDP, TS_ENCODING)) { flags |= NI_DGRAM.value; } - Object[] result = posixLib.getnameinfo(getPosixSupport(), addr, flags); - TruffleString name = posixLib.getCStringAsString(getPosixSupport(), result[1]); - checkName(name); - return name; + result = getPosixSupport().getnameinfo(addr, flags); } finally { gil.acquire(); } + TruffleString name = getCStringAsStringNode.execute(inliningTarget, getPosixSupport(), result[1]); + checkName(name); + return name; } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); } catch (PosixException e) { @@ -557,13 +556,12 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, @Bind PythonContext context, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoCursorLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary sockAddrLibrary, @Cached GilNode gil, @Cached SequenceStorageNodes.GetItemScalarNode getItem, @Cached CastToTruffleStringNode castAddress, @Cached PyLongAsIntNode asIntNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.FromLongNode fromLongNode, @@ -597,21 +595,22 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, try { UniversalSockAddr resolvedAddr; int family; + PosixSupport posixSupport = context.getPosixSupport(); + Object addressOpaque = createCStringFromStringNode.execute(inliningTarget, posixSupport, address); + Object portOpaque = createCStringFromStringNode.execute(inliningTarget, posixSupport, fromLongNode.execute(port, TS_ENCODING, false)); // TODO getaddrinfo lock? gil.release(true); - PosixSupport posixSupport = context.getPosixSupport(); try { - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromString(posixSupport, address), - posixLib.createCStringFromString(posixSupport, fromLongNode.execute(port, TS_ENCODING, false)), + AddrInfoCursor cursor = posixSupport.getaddrinfo(addressOpaque, portOpaque, AF_UNSPEC.value, SOCK_DGRAM.value, 0, AI_NUMERICHOST.value); try { - family = addrInfoCursorLib.getFamily(cursor); - resolvedAddr = addrInfoCursorLib.getSockAddr(cursor); - if (addrInfoCursorLib.next(cursor)) { + family = cursor.getFamily(); + resolvedAddr = cursor.getSockAddr(); + if (cursor.next()) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SOCKADDR_RESOLVED_TO_MULTIPLE_ADDRESSES); } } finally { - addrInfoCursorLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); @@ -622,16 +621,16 @@ static Object getNameInfo(VirtualFrame frame, Object sockaddr, int flags, if (addrLen != 2) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.IPV4_MUST_BE_2_TUPLE); } - queryAddr = posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(port, sockAddrLibrary.asInet4SockAddr(resolvedAddr).getAddress())); + queryAddr = posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(port, resolvedAddr.asInet4SockAddr().getAddress())); } else if (family == AF_INET6.value) { - queryAddr = posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(port, sockAddrLibrary.asInet6SockAddr(resolvedAddr).getAddress(), flowinfo, scopeid)); + queryAddr = posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(port, resolvedAddr.asInet6SockAddr().getAddress(), flowinfo, scopeid)); } else { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.UNKNOWN_FAMILY); } - Object[] getnameinfo = posixLib.getnameinfo(posixSupport, queryAddr, flags); - TruffleString host = posixLib.getCStringAsString(posixSupport, getnameinfo[0]); - TruffleString service = posixLib.getCStringAsString(posixSupport, getnameinfo[1]); + Object[] getnameinfo = posixSupport.getnameinfo(queryAddr, flags); + TruffleString host = getCStringAsStringNode.execute(inliningTarget, posixSupport, getnameinfo[0]); + TruffleString service = getCStringAsStringNode.execute(inliningTarget, posixSupport, getnameinfo[1]); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{host, service}); } catch (GetAddrInfoException e) { throw constructAndRaiseNode.get(inliningTarget).executeWithArgsOnly(frame, SocketGAIError, new Object[]{e.getErrorCode(), e.getMessageAsTruffleString()}); @@ -664,8 +663,6 @@ public abstract static class GetAddrInfoNode extends PythonClinicBuiltinNode { static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObject, int family, int type, int proto, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary cursorLib, @Cached InlinedExactClassProfile profile, @Cached("createIdna()") IdnaFromStringOrBytesConverterNode idna, @Cached PyLongAsLongNode asLongNode, @@ -676,22 +673,24 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached TruffleString.FromLongNode fromLongNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object host = null; PosixSupport posixSupport = context.getPosixSupport(); if (hostObject != PNone.NONE) { - host = posixLib.createCStringFromBytes(posixSupport, idna.execute(frame, hostObject)); + host = posixSupport.createCStringFromBytes(idna.execute(frame, hostObject)); } Object port; Object portObjectProfiled = profile.profile(inliningTarget, portObject); if (PGuards.canBeInteger(portObjectProfiled)) { - port = posixLib.createCStringFromString(posixSupport, fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); + port = createCStringFromStringNode.execute(inliningTarget, posixSupport, fromLongNode.execute(asLongNode.execute(frame, inliningTarget, portObjectProfiled), TS_ENCODING, false)); } else if (PGuards.isString(portObjectProfiled)) { - port = posixLib.createCStringFromString(posixSupport, castToString.execute(inliningTarget, portObjectProfiled)); + port = createCStringFromStringNode.execute(inliningTarget, posixSupport, castToString.execute(inliningTarget, portObjectProfiled)); } else if (PGuards.isBytes(portObjectProfiled)) { - port = posixLib.createCStringFromBytes(posixSupport, toBytes.execute(frame, portObjectProfiled)); + port = posixSupport.createCStringFromBytes(toBytes.execute(frame, portObjectProfiled)); } else if (portObject == PNone.NONE) { port = null; } else { @@ -705,7 +704,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje // TODO getaddrinfo lock gil.release(true); try { - cursor = posixLib.getaddrinfo(posixSupport, host, port, family, type, proto, flags); + cursor = posixSupport.getaddrinfo(host, port, family, type, proto, flags); } finally { gil.acquire(); } @@ -717,18 +716,19 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje try { SequenceStorage storage = new ObjectSequenceStorage(5); do { - Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursorLib.getSockAddr(cursor)); + Object addr = makeSockAddrNode.execute(frame, inliningTarget, cursor.getSockAddr()); TruffleString canonName = T_EMPTY_STRING; - if (cursorLib.getCanonName(cursor) != null) { - canonName = posixLib.getCStringAsString(posixSupport, cursorLib.getCanonName(cursor)); + if (cursor.getCanonName() != null) { + canonName = getCStringAsStringNode.execute(inliningTarget, posixSupport, cursor.getCanonName()); } PTuple tuple = PFactory.createTuple(context.getLanguage(inliningTarget), - new Object[]{cursorLib.getFamily(cursor), cursorLib.getSockType(cursor), cursorLib.getProtocol(cursor), canonName, addr}); + new Object[]{cursor.getFamily(), cursor.getSockType(), cursor.getProtocol(), canonName, addr}); storage = appendNode.execute(inliningTarget, storage, tuple, SequenceStorageNodes.ListGeneralizationNode.SUPPLIER); - } while (cursorLib.next(cursor)); + } while (cursor.next()); + LoopNode.reportLoopCount(inliningTarget, storage.length()); return PFactory.createList(context.getLanguage(inliningTarget), storage); } finally { - cursorLib.release(cursor); + cursor.release(); } } @@ -749,7 +749,6 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization static Object close(VirtualFrame frame, Object fdObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached GilNode gil, @Cached PyLongAsIntNode asIntNode, @@ -758,7 +757,7 @@ static Object close(VirtualFrame frame, Object fdObj, try { gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } @@ -778,7 +777,6 @@ abstract static class DupNode extends PythonUnaryBuiltinNode { @Specialization static Object close(VirtualFrame frame, Object fdObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached GilNode gil, @Cached PyLongAsIntNode asIntNode, @@ -787,12 +785,12 @@ static Object close(VirtualFrame frame, Object fdObj, try { gil.release(true); try { - int dup = posixLib.dup(context.getPosixSupport(), fd); + int dup = context.getPosixSupport().dup(fd); try { - posixLib.setInheritable(context.getPosixSupport(), dup, false); + context.getPosixSupport().setInheritable(dup, false); } catch (PosixException e1) { try { - posixLib.close(context.getPosixSupport(), dup); + context.getPosixSupport().close(dup); } catch (PosixException e2) { // ignore } @@ -815,15 +813,15 @@ abstract static class InetAtoNNode extends PythonUnaryClinicBuiltinNode { static PBytes doConvert(TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - int converted = posixLib.inet_aton(posixSupport, posixLib.createCStringFromString(posixSupport, addr)); + int converted = posixSupport.inet_aton(createCStringFromStringNode.execute(inliningTarget, posixSupport, addr)); byte[] bytes = new byte[4]; ByteArraySupport.bigEndian().putInt(bytes, 0, converted); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); - } catch (PosixSupportLibrary.InvalidAddressException e) { + } catch (PosixSupport.InvalidAddressException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ILLEGAL_IP_ADDR_STRING_TO_INET_ATON); } } @@ -844,7 +842,7 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, @CachedLibrary("addr") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(addr, frame, callData); try { @@ -854,8 +852,8 @@ static TruffleString doGeneric(VirtualFrame frame, Object addr, throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.PACKED_IP_WRONG_LENGTH, "inet_ntoa"); } PosixSupport posixSupport = context.getPosixSupport(); - Object result = posixLib.inet_ntoa(posixSupport, ByteArraySupport.bigEndian().getInt(bytes, 0)); - return posixLib.getCStringAsString(posixSupport, result); + Object result = posixSupport.inet_ntoa(ByteArraySupport.bigEndian().getInt(bytes, 0)); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, result); } finally { bufferLib.release(buffer, frame, callData); } @@ -871,16 +869,16 @@ abstract static class InetPtoNNode extends PythonBinaryClinicBuiltinNode { static PBytes doConvert(VirtualFrame frame, int family, TruffleString addr, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { PosixSupport posixSupport = context.getPosixSupport(); - byte[] bytes = posixLib.inet_pton(posixSupport, family, posixLib.createCStringFromString(posixSupport, addr)); + byte[] bytes = posixSupport.inet_pton(family, createCStringFromStringNode.execute(inliningTarget, posixSupport, addr)); return PFactory.createBytes(context.getLanguage(inliningTarget), bytes); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); - } catch (PosixSupportLibrary.InvalidAddressException e) { + } catch (PosixSupport.InvalidAddressException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ILLEGAL_IP_ADDR_STRING_TO_INET_PTON); } } @@ -902,7 +900,7 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, @CachedLibrary("obj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { Object buffer = bufferAcquireLib.acquireReadonly(obj, frame, callData); @@ -922,8 +920,8 @@ static TruffleString doGeneric(VirtualFrame frame, int family, Object obj, } try { PosixSupport posixSupport = context.getPosixSupport(); - Object result = posixLib.inet_ntop(posixSupport, family, bytes); - return posixLib.getCStringAsString(posixSupport, result); + Object result = posixSupport.inet_ntop(family, bytes); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, result); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java index cb1cd7b2ef..50f5f40636 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/StringModuleBuiltins.java @@ -66,6 +66,8 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @CoreFunctions(defineModule = J__STRING) @@ -97,15 +99,16 @@ PSequenceIterator formatterParser(VirtualFrame frame, TruffleString self, } finally { ExecutionContext.BoundaryCallContext.exit(frame, language, context, state); } - return parserListToIterator(parserList, language); + return parserListToIterator(this, parserList, language); } } - private static PSequenceIterator parserListToIterator(ArrayList parserList, PythonLanguage language) { + private static PSequenceIterator parserListToIterator(Node inliningTarget, ArrayList parserList, PythonLanguage language) { Object[] tuples = new Object[parserList.size()]; for (int i = 0; i < tuples.length; i++) { tuples[i] = PFactory.createTuple(language, parserList.get(i)); } + LoopNode.reportLoopCount(inliningTarget, tuples.length); return PFactory.createSequenceIterator(language, PFactory.createList(language, tuples)); } @@ -131,7 +134,7 @@ Object formatterParser(VirtualFrame frame, TruffleString self, } finally { ExecutionContext.BoundaryCallContext.exit(frame, language, context, state); } - return PFactory.createTuple(language, new Object[]{result.first, parserListToIterator(result.parserList, language)}); + return PFactory.createTuple(language, new Object[]{result.first, parserListToIterator(this, result.parserList, language)}); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index c757647e9e..909f0b0685 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -50,6 +50,7 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.DeprecationWarning; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ImportError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeWarning; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; @@ -174,6 +175,7 @@ import com.oracle.graal.python.builtins.modules.io.PFileIO; import com.oracle.graal.python.builtins.modules.io.PTextIO; import com.oracle.graal.python.builtins.modules.io.TextIOWrapperNodesFactory.TextIOWrapperInitNodeGen; +import com.oracle.graal.python.builtins.modules.io.WindowsConsoleIOBuiltins; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; @@ -254,8 +256,8 @@ import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.WindowsVersion; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.CApiState; import com.oracle.graal.python.runtime.PythonImageBuildOptions; @@ -286,6 +288,7 @@ import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -798,8 +801,7 @@ static void initStd(Python3Core core) { GraalPythonModuleBuiltins gp = (GraalPythonModuleBuiltins) core.lookupBuiltinModule(T___GRAALPYTHON__).getBuiltins(); TruffleString stdioEncoding = gp.getStdIOEncoding(); TruffleString stdioError = gp.getStdIOError(); - Object posixSupport = context.getPosixSupport(); - PosixSupportLibrary posixLib = PosixSupportLibrary.getUncached(); + PosixSupport posixSupport = context.getPosixSupport(); PythonModule sysModule = core.lookupBuiltinModule(T_SYS); boolean buffering = !context.getOption(PythonOptions.UnbufferedIO); @@ -807,26 +809,48 @@ static void initStd(Python3Core core) { PFileIO stdinFileIO = PFactory.createFileIO(language); FileIOBuiltins.FileIOInit.internalInit(stdinFileIO, toTruffleStringUncached(""), 0, IOMode.RB); PBuffered stdinBuffer = PFactory.createBufferedReader(language); - BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + BufferedReaderBuiltins.BufferedReaderInit.internalInit(stdinBuffer, stdinFileIO, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport); setWrapper(T_STDIN, T___STDIN__, T_R, stdioEncoding, stdioError, PNone.NONE, stdinBuffer, sysModule, language, true); - PFileIO stdoutFileIO = PFactory.createFileIO(language); - FileIOBuiltins.FileIOInit.internalInit(stdoutFileIO, toTruffleStringUncached(""), 1, IOMode.WB); - Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport, posixLib); - setWrapper(T_STDOUT, T___STDOUT__, T_W, stdioEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); + PFileIO stdoutFileIO = createStdoutRaw(context, language, toTruffleStringUncached(""), 1); + Object stdoutBuffer = createBufferedIO(buffering, language, stdoutFileIO, posixSupport); + TruffleString stdoutEncoding = isWindowsConsoleIO(stdoutFileIO) ? StringLiterals.T_UTF8 : stdioEncoding; + setWrapper(T_STDOUT, T___STDOUT__, T_W, stdoutEncoding, stdioError, PNone.NONE, stdoutBuffer, sysModule, language, buffering); - PFileIO stderr = PFactory.createFileIO(language); - FileIOBuiltins.FileIOInit.internalInit(stderr, toTruffleStringUncached(""), 2, IOMode.WB); - Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport, posixLib); - setWrapper(T_STDERR, T___STDERR__, T_W, stdioEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); + PFileIO stderr = createStdoutRaw(context, language, toTruffleStringUncached(""), 2); + Object stderrBuffer = createBufferedIO(buffering, language, stderr, posixSupport); + TruffleString stderrEncoding = isWindowsConsoleIO(stderr) ? StringLiterals.T_UTF8 : stdioEncoding; + setWrapper(T_STDERR, T___STDERR__, T_W, stderrEncoding, T_BACKSLASHREPLACE, PNone.NONE, stderrBuffer, sysModule, language, buffering); } - private static Object createBufferedIO(boolean buffering, PythonLanguage language, PFileIO fileIo, Object posixSupport, PosixSupportLibrary posixLib) { + private static PFileIO createStdoutRaw(PythonContext context, PythonLanguage language, TruffleString name, int fd) { + if (getPythonOS() == PLATFORM_WIN32 && !context.getOption(PythonOptions.LegacyWindowsStdio)) { + int consoleType = context.getPosixSupport().getWindowsConsoleType(fd); + if (consoleType != 0) { + PFileIO consoleIO = WindowsConsoleIOBuiltins.create(language); + WindowsConsoleIOBuiltins.internalInit(consoleIO, name, fd, IOMode.WB, consoleType); + return consoleIO; + } + } + PFileIO fileIO = PFactory.createFileIO(language); + FileIOBuiltins.FileIOInit.internalInit(fileIO, name, fd, IOMode.WB); + return fileIO; + } + + private static boolean isWindowsConsoleIO(PFileIO fileIO) { + return getPythonOS() == PLATFORM_WIN32 && fileIO.getPythonClass() == PWindowsConsoleIO; + } + + private static Object createBufferedIO(boolean buffering, PythonLanguage language, PFileIO fileIo, PosixSupport posixSupport) { if (!buffering) { return fileIo; } PBuffered writer = PFactory.createBufferedWriter(language); - BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport, posixLib); + if (isWindowsConsoleIO(fileIo)) { + BufferedWriterBuiltins.BufferedWriterInit.internalInitConsole(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language); + } else { + BufferedWriterBuiltins.BufferedWriterInit.internalInit(writer, fileIo, BufferedReaderBuiltins.DEFAULT_BUFFER_SIZE, language, posixSupport); + } return writer; } @@ -1260,6 +1284,7 @@ static void doAudit(VirtualFrame frame, Node inliningTarget, TruffleString event for (Object hook : hooks) { callNode.get(inliningTarget).execute(frame, hook, event, argsTuple); } + LoopNode.reportLoopCount(inliningTarget, hooks.length); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java index 3a6a3ad5b0..25f58f9575 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TypingModuleBuiltins.java @@ -83,6 +83,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -254,12 +255,14 @@ static PTuple doUnpack(VirtualFrame frame, Node inliningTarget, PTuple params, @Cached UnpackNode unpackNode) { Object[] elements = toArrayNode.execute(inliningTarget, params.getSequenceStorage()); boolean found = false; - for (Object element : elements) { - if (element instanceof PTypeVarTuple) { + int index = 0; + for (; index < elements.length; index++) { + if (elements[index] instanceof PTypeVarTuple) { found = true; break; } } + LoopNode.reportLoopCount(inliningTarget, index); if (!found) { return params; } @@ -271,6 +274,7 @@ static PTuple doUnpack(VirtualFrame frame, Node inliningTarget, PTuple params, unpacked[i] = elements[i]; } } + LoopNode.reportLoopCount(inliningTarget, unpacked.length); return PFactory.createTuple(language, unpacked); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java index 37e60023cd..a186658601 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WarningsModuleBuiltins.java @@ -141,6 +141,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -1016,6 +1017,7 @@ Object doWarn(VirtualFrame frame, PythonModule mod, Object message, Object categ Object item = getItemScalarNode.execute(inliningTarget, storage, i); skipFilePrefixes[i] = castToStringChecked.cast(inliningTarget, item, ErrorMessages.FOUND_NON_STR_S_IN_SKIP_FILE_PREFIXES, item); } + LoopNode.reportLoopCount(inliningTarget, skipFilePrefixes.length); if (stacklevel < 2) { stacklevel = 2; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java index 3212366bb2..cc95ae9f93 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstBuiltins.java @@ -101,6 +101,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.AST) @@ -159,6 +160,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] setAttrNode.execute(frame, inliningTarget, self, field, args[i]); discardNode.execute(frame, remainingFields, field); } + LoopNode.reportLoopCount(inliningTarget, args.length); Object selfType = getClassNode.execute(inliningTarget, self); for (PKeyword kwArg : kwArgs) { if (containsNode.execute(frame, inliningTarget, fieldsObj, kwArg.getName())) { @@ -173,6 +175,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] } setAttrNode.execute(frame, inliningTarget, self, kwArg.getName(), kwArg.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwArgs.length); if (storageLenNode.execute(inliningTarget, remainingFields.getDictStorage()) > 0) { Object fieldTypesObj = lookupAttrNode.execute(frame, inliningTarget, selfType, T__FIELD_TYPES); if (!(fieldTypesObj instanceof PDict fieldTypes)) { @@ -195,6 +198,7 @@ protected Object doIt(VirtualFrame frame, Object self, Object[] args, PKeyword[] } } } + LoopNode.reportLoopCount(inliningTarget, numFields); } return PNone.NONE; } @@ -253,6 +257,7 @@ static Object doit(VirtualFrame frame, PythonObject self, Object ignored, } numPositionalArgs++; } + LoopNode.reportLoopCount(inliningTarget, numFields); PNone[] positionalArgs = new PNone[numPositionalArgs]; Arrays.fill(positionalArgs, PNone.NONE); return PFactory.createTuple(language, new Object[]{clazz, PFactory.createTuple(language, positionalArgs), dict}); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java index ef89e1b0d5..1ace10234d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java @@ -161,7 +161,7 @@ import com.oracle.graal.python.nodes.statement.AbstractImportNode; import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.ExceptionUtils; @@ -1587,8 +1587,8 @@ static long GraalPyPrivate_GetMMapData(long objectPtr) { PMMap object = (PMMap) NativeToPythonInternalNode.executeUncached(objectPtr, false); PythonContext context = PythonContext.get(null); try { - return PosixSupportLibrary.getUncached().mmapGetPointer(context.getPosixSupport(), object.getPosixSupportHandle()); - } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { + return context.getPosixSupport().mmapGetPointer(object.getPosixSupportHandle()); + } catch (PosixSupport.UnsupportedPosixFeatureException e) { throw PConstructAndRaiseNode.getUncached().raiseOSErrorUnsupported(null, e); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java index 7694a37392..bcaf6b1404 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextDictBuiltins.java @@ -143,6 +143,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -243,6 +244,7 @@ static int next(PDict dict, long posPtr, long keyPtr, long valuePtr, long hashPt break; } } + LoopNode.reportLoopCount(inliningTarget, len); } else { /* * Other storages always have string keys or have complex iterators, just @@ -268,6 +270,7 @@ static int next(PDict dict, long posPtr, long keyPtr, long valuePtr, long hashPt // promoted key will never have side-effecting __hash__/__eq__ setItem.execute(null, inliningTarget, newStorage, key, value); } + LoopNode.reportLoopCount(inliningTarget, len); dict.setDictStorage(newStorage); if (storage instanceof DynamicObjectStorage dynamicStorage && dynamicStorage.getStore() instanceof PythonObject owner) { @@ -888,6 +891,7 @@ static int merge(PDict a, Object b, @SuppressWarnings("unused") int override, aStorage = setItemA.execute(null, inliningTarget, aStorage, key, value); } } + LoopNode.reportLoopCount(inliningTarget, size); a.setDictStorage(aStorage); return 0; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 5f115f4d17..0719aa213a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -50,6 +50,7 @@ import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObject; +import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectAsTruffleString; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectConstPtr; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectPtr; import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectRawPointer; @@ -65,12 +66,14 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___BYTES__; import static com.oracle.graal.python.nodes.StringLiterals.T_JAVA; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.POINTER_SIZE; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.readPtrArrayElement; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.writePtr; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import java.io.PrintWriter; import java.lang.ref.Reference; +import java.util.logging.Level; import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; @@ -88,6 +91,8 @@ import com.oracle.graal.python.builtins.objects.bytes.BytesNodes; import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; +import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTiming; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions; @@ -119,6 +124,8 @@ import com.oracle.graal.python.lib.PyObjectGetAttr; import com.oracle.graal.python.lib.PyObjectGetAttrO; import com.oracle.graal.python.lib.PyObjectGetIter; +import com.oracle.graal.python.lib.PyObjectGetMethod; +import com.oracle.graal.python.lib.PyObjectGetMethodNodeGen; import com.oracle.graal.python.lib.PyObjectHashNode; import com.oracle.graal.python.lib.PyObjectIsInstanceNode; import com.oracle.graal.python.lib.PyObjectIsSubclassNode; @@ -136,6 +143,8 @@ import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; +import com.oracle.graal.python.nodes.builtins.TupleNodesFactory.GetTupleStorageNodeGen; +import com.oracle.graal.python.nodes.call.BoundDescriptor; import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode; import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode; @@ -145,7 +154,7 @@ import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -156,12 +165,13 @@ import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -225,6 +235,7 @@ static Object doLong(long arrayPointer, int len, pointers[i] = elem; resolved[i] = nativeToPythonNode.execute(inliningTarget, elem); } + LoopNode.reportLoopCount(inliningTarget, resolved.length); HandleContext handleContext = PythonContext.get(inliningTarget).handleContext; for (int i = 0; i < resolved.length; i++) { long refCount = CApiTransitions.readNativeRefCount(pointers[i]); @@ -242,6 +253,7 @@ static Object doLong(long arrayPointer, int len, updateRefNode.execute(inliningTarget, handleContext, pointers[i], hti, refCount); } } + LoopNode.reportLoopCount(inliningTarget, resolved.length); Reference.reachabilityFence(resolved); return PNone.NO_VALUE; } @@ -284,6 +296,61 @@ static Object doMethod(Object receiver, Object methodName, long argsArray, long } } + @CApiBuiltin(ret = Int, args = {PyObjectAsTruffleString, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject, PyObjectPtr}, call = Ignored) + static int GraalPyPrivate_Object_VectorcallMethod(long methodNamePtr, long receiverPtr, long argsArray, long nargs, long kwnamesPtr, long resultPointer) { + TruffleString methodName = CastToTruffleStringNode.castKnownStringUncached(NativeToPythonInternalNode.executeUncached(methodNamePtr, false)); + Object receiver = NativeToPythonInternalNode.executeUncached(receiverPtr, false); + long resultPointerValue = NULLPTR; + try { + Object callable = PyObjectGetMethodNodeGen.getUncached().execute(null, null, receiver, methodName); + boolean isBound = callable instanceof BoundDescriptor; + if (!isBound && callable instanceof PythonAbstractNativeObject) { + resultPointerValue = PythonToNativeInternalNode.executeNewRefUncached(callable); + return 1; + } + Object[] args = readArguments(argsArray, (int) nargs, receiver, isBound); + if (isBound) { + callable = ((BoundDescriptor) callable).descriptor; + } + + PKeyword[] keywords; + if (kwnamesPtr == NULLPTR) { + keywords = PKeyword.EMPTY_KEYWORDS; + } else { + Object keywordNames = NativeToPythonInternalNode.executeUncached(kwnamesPtr, false); + SequenceStorage storage = GetTupleStorageNodeGen.getUncached().execute(null, keywordNames); + int kwcount = storage.length(); + Object[] kwValues = CStructAccess.ReadObjectNode.getUncached().readPyObjectArray(argsArray, kwcount, (int) nargs); + keywords = new PKeyword[kwcount]; + for (int i = 0; i < kwcount; i++) { + TruffleString name = CastToTruffleStringNode.executeUncached(SequenceStorageNodes.GetItemScalarNode.executeUncached(storage, i)); + keywords[i] = new PKeyword(name, kwValues[i]); + } + } + Object result = CallNode.executeUncached(callable, args, keywords); + resultPointerValue = PythonToNativeInternalNode.executeNewRefUncached(result); + return 0; + } catch (CannotCastException e) { + // PyVectorcall_NARGS cannot exceed Py_ssize_t, and GraalPy arrays are int-sized. + throw CompilerDirectives.shouldNotReachHere(e); + } finally { + writePtr(resultPointer, resultPointerValue); + } + } + + private static Object[] readArguments(long argsArray, int nargs, + Object receiver, boolean isBound) { + if (isBound) { + return CStructAccess.ReadObjectNode.getUncached().readPyObjectArray(argsArray, nargs); + } + Object[] args = new Object[nargs + 1]; + args[0] = receiver; + for (int i = 0; i < nargs; i++) { + args[i + 1] = CStructAccess.ReadObjectNode.getUncached().read(argsArray, i * POINTER_SIZE); + } + return args; + } + @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, ConstCharPtrAsTruffleString, PyObject, Int}, call = Ignored) abstract static class GraalPyPrivate_Object_CallMethod1 extends CApiQuaternaryBuiltinNode { @Specialization @@ -306,6 +373,8 @@ static Object doGeneric(Object receiver, TruffleString methodName, Object argsOb @CApiBuiltin(ret = PyObjectTransfer, args = {PyThreadState, PyObject, PyObjectConstPtr, Py_ssize_t, PyObject}, call = Direct) abstract static class _PyObject_MakeTpCall extends CApi5BuiltinNode { + private static final TruffleLogger LOGGER = CApiContext.getLogger(_PyObject_MakeTpCall.class); + @Specialization static Object doGeneric(@SuppressWarnings("unused") long threadState, Object callable, long argsArray, long nargs, Object kwargs, @Cached CStructAccess.ReadObjectNode readNode, @@ -318,6 +387,9 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal @Cached PyTupleCheckNode tupleCheckNode, @Cached CastToTruffleStringNode castToTruffleStringNode) { try { + if (LOGGER.isLoggable(Level.FINE)) { + logCallableType(callable); + } Object[] args = readNode.readPyObjectArray(argsArray, (int) nargs); PKeyword[] keywords; @@ -335,6 +407,7 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal TruffleString name = castToTruffleStringNode.execute(inliningTarget, getItemScalarNode.execute(inliningTarget, storage, i)); keywords[i] = new PKeyword(name, kwValues[i]); } + LoopNode.reportLoopCount(inliningTarget, kwcount); } else { throw CompilerDirectives.shouldNotReachHere("_PyObject_MakeTpCall: keywords must be NULL, a tuple or a dict"); } @@ -345,6 +418,12 @@ static Object doGeneric(@SuppressWarnings("unused") long threadState, Object cal throw CompilerDirectives.shouldNotReachHere(e); } } + + @TruffleBoundary + private static void logCallableType(Object callable) { + Object type = GetClassNode.executeUncached(callable); + LOGGER.fine(TypeNodes.GetNameNode.executeUncached(type).toJavaStringUncached()); + } } @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct) @@ -423,13 +502,12 @@ abstract static class PyObject_AsFileDescriptor extends CApiUnaryBuiltinNode { static Object asFileDescriptor(Object obj, @Bind Node inliningTarget, @Cached PyLongCheckNode longCheckNode, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached TruffleString.EqualNode eqNode, @Cached PyObjectAsFileDescriptor asFileDescriptorNode, @Cached PRaiseNode raiseNode) { if (!longCheckNode.execute(inliningTarget, obj)) { - Object posixSupport = PythonContext.get(inliningTarget).getPosixSupport(); - if (eqNode.execute(T_JAVA, posixLib.getBackend(posixSupport), TS_ENCODING)) { + PosixSupport posixSupport = PythonContext.get(inliningTarget).getPosixSupport(); + if (eqNode.execute(T_JAVA, posixSupport.getBackend(), TS_ENCODING)) { /* * For non Python 'int' objects, we refuse to hand out the fileno field when * using the emulated Posix backend, because it is likely a fake. @@ -483,6 +561,32 @@ static int getOptionalAttr(Object obj, Object attr, long resultPointer, } } + @CApiBuiltin(ret = Int, args = {PyObject, PyObjectAsTruffleString, PyObjectPtr}, call = Ignored) + abstract static class GraalPyPrivate_Object_GetMethod extends CApiTernaryBuiltinNode { + @Specialization + static int getMethod(Object receiver, TruffleString name, long resultPointer, + @Bind Node inliningTarget, + @Bind PythonContext context, + @Cached PyObjectGetMethod getMethodNode, + @Cached EnsurePythonObjectNode ensureNode, + @Cached PythonToNativeInternalNode toNativeNode, + @Cached InlinedConditionProfile isBoundProfile) { + long resultPointerValue = NULLPTR; + try { + Object result = getMethodNode.execute(null, inliningTarget, receiver, name); + boolean isBound = isBoundProfile.profile(inliningTarget, result instanceof BoundDescriptor); + if (isBound) { + result = ((BoundDescriptor) result).descriptor; + } + resultPointerValue = toNativeNode.executeNewRef(inliningTarget, + ensureNode.execute(context, result, false)); + return isBound ? 0 : 1; + } finally { + writePtr(resultPointer, resultPointerValue); + } + } + } + @CApiBuiltin(ret = Int, args = {PyObject, ConstCharPtr, PyObjectPtr}, call = Ignored) abstract static class GraalPyPrivate_Object_GetOptionalAttrString extends CApiTernaryBuiltinNode { @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java index c5b2d46b31..691e893535 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java @@ -133,6 +133,7 @@ import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.Shape; @@ -188,11 +189,14 @@ Object doGeneric(Object type, Object name, } else { setItem.execute(null, inliningTarget, dict, key, promoted); } + LoopNode.reportLoopCount(inliningTarget, i); return promoted; } + LoopNode.reportLoopCount(inliningTarget, i); return value; } } + LoopNode.reportLoopCount(inliningTarget, mro.length()); return NATIVE_NULL; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java index 5cd0f27dc1..7e67ff7c82 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextUnicodeBuiltins.java @@ -189,6 +189,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.nodes.ControlFlowException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedExactClassProfile; @@ -489,6 +490,7 @@ static Object formatLong(Object val, int alt, int prec, int type, for (int i = 0; i < prec - numdigits; i++) { b1[b1i++] = '0'; } + LoopNode.reportLoopCount(inliningTarget, prec - numdigits); for (int i = 0; i < numdigits; i++) { b1[b1i++] = buf[bufi++]; b1[b1i] = '\0'; @@ -508,6 +510,7 @@ static Object formatLong(Object val, int alt, int prec, int type, buf[i] -= 'a' - 'A'; } } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, len - bufi)); } return fromCharArrayNode.execute(buf); } @@ -848,6 +851,7 @@ static Object join(Object separatorObj, long itemsObj, long seqlenlong, } appendStringNode.execute(sb, item); } + LoopNode.reportLoopCount(inliningTarget, items.length); return toStringNode.execute(sb); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java index 40317f7de0..208c54b469 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cjkcodecs/MultibyteStreamWriterBuiltins.java @@ -82,6 +82,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -186,6 +187,7 @@ static Object doGeneric(VirtualFrame frame, MultibyteStreamWriterObject self, Ob Object str = encodeStatefulNode.execute(frame, self, strobj, 0); callMethod.execute(frame, inliningTarget, self.stream, WRITE, str); } + LoopNode.reportLoopCount(inliningTarget, n); return PNone.NONE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java index 5c14430531..f8c85b8a89 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/codecs/ErrorHandlers.java @@ -112,6 +112,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -376,11 +377,13 @@ static Object doEncode(PBaseException exception, for (int i = start; i < end; ++i) { replacementLength += getXmlCharRefReplacementLength(codePointAtIndexNode.execute(src, i)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); byte[] replacement = new byte[replacementLength]; int pos = 0; for (int i = start; i < end; ++i) { pos = appendXmlCharRefReplacement(replacement, pos, codePointAtIndexNode.execute(src, i)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); TruffleString resultAscii = fromByteArrayNode.execute(replacement, 0, replacement.length, TruffleString.CompactionLevel.S1, false); return PFactory.createTuple(language, new Object[]{resultAscii, end}); } @@ -423,6 +426,7 @@ static Object doDecodeException(VirtualFrame frame, PBaseException exception, for (int i = start; i < end; i++) { pos = BytesUtils.byteEscape(src[i] & 0xFF, pos, replacement); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); } finally { accessLib.release(srcBuf, frame, callData); } @@ -457,12 +461,14 @@ static Object doEncodeOrTranslateException(PBaseException exception, len += 1 + 1 + 2; // \\xNN } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); byte[] replacement = new byte[len]; int pos = 0; for (int i = start; i < end; i++) { int cp = codePointAtIndexNode.execute(src, i); pos = BytesUtils.unicodeNonAsciiEscape(cp, pos, replacement, true); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); TruffleString resultAscii = fromByteArrayNode.execute(replacement, 0, replacement.length, TruffleString.CompactionLevel.S1, false); return PFactory.createTuple(language, new Object[]{resultAscii, end}); } @@ -515,6 +521,7 @@ static Object doEncode(PBaseException exception, appendStringNode.execute(tsb, fromByteArrayNode.execute(buf, 0, len, TruffleString.CompactionLevel.S1, true)); } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{toStringNode.execute(tsb), end}); } @@ -563,6 +570,7 @@ static Object doEncode(PBaseException exception, encodeCodepoint(encoding, result, pos, cp); pos += encoding.byteLength; } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{PFactory.createBytes(language, result), end}); } @@ -691,6 +699,7 @@ static Object doEncode(PBaseException exception, } result[pos++] = (byte) (cp - 0xdc00); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) end - start))); return PFactory.createTuple(language, new Object[]{PFactory.createBytes(language, result), end}); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java index 371f6861db..484ec5e9da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/LruCacheWrapperBuiltins.java @@ -1,5 +1,5 @@ /* - * 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 @@ -104,6 +104,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -320,6 +321,7 @@ static Object lruCacheMakeKey(Object kwdMark, Object[] args, PKeyword[] kwds, in } } } + LoopNode.reportLoopCount(inliningTarget, keyPos - kwdsSize - (kwdsSize != 0 ? 1 : 0)); assert (keyPos == keySize); return PFactory.createTuple(PythonLanguage.get(inliningTarget), keyArray); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java index 6cd8fedd46..a79f81ab0a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/functools/PartialBuiltins.java @@ -127,6 +127,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -500,6 +501,7 @@ static Object callWDictWKw(VirtualFrame frame, PPartial self, Object[] args, PKe callKeywords[idx] = kw; } } + LoopNode.reportLoopCount(inliningTarget, keywords.length); callKeywords = PythonUtils.arrayCopyOfRange(callKeywords, 0, kwIndex); return callNode.execute(frame, self.getFn(), callArgs, callKeywords); @@ -511,10 +513,12 @@ static Object callWDictWKw(VirtualFrame frame, PPartial self, Object[] args, PKe abstract static class PartialReprNode extends PythonUnaryBuiltinNode { private static void reprArgs(VirtualFrame frame, Node inliningTarget, PPartial partial, TruffleStringBuilderUTF32 sb, PyObjectReprAsTruffleStringNode reprNode, TruffleStringBuilder.AppendStringNode appendStringNode) { - for (Object arg : partial.getArgs()) { + Object[] args = partial.getArgs(); + for (int i = 0; i < args.length; i++) { appendStringNode.execute(sb, T_COMMA_SPACE); - appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, arg)); + appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); } private static void reprKwArgs(VirtualFrame frame, Node inliningTarget, PPartial partial, TruffleStringBuilderUTF32 sb, PyObjectReprAsTruffleStringNode reprNode, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java index 63de30bfea..bc9e122cca 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/AbstractBufferedIOBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -64,8 +64,8 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.CompilerDirectives; @@ -104,7 +104,7 @@ static void bufferSizeError(PBuffered self, int bufferSize, throw PRaiseNode.raiseStatic(inliningTarget, ValueError, BUF_SIZE_POS); } - private static void init(PBuffered self, int bufferSize, PythonLanguage language) { + static void init(PBuffered self, int bufferSize, PythonLanguage language) { self.initBuffer(bufferSize); self.setLock(PFactory.createLock(language)); self.setOwner(0); @@ -116,11 +116,10 @@ private static void init(PBuffered self, int bufferSize, PythonLanguage language } public static void internalInit(PBuffered self, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { init(self, bufferSize, language); try { - FileIOBuiltins.TellNode.internalTell(self.getFileIORaw(), posixSupport, posixLib); + FileIOBuiltins.TellNode.internalTell(self.getFileIORaw(), posixSupport); } catch (PosixException e) { // ignore.. it's ok if it's not seekable } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java index 577b1f4413..7d4bf8f95c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedReaderBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -116,11 +116,10 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PBuffered self, Obje } public static void internalInit(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { self.setDetached(false); self.setRaw(raw, true); - BufferedInitNode.internalInit(self, bufferSize, language, posixSupport, posixLib); + BufferedInitNode.internalInit(self, bufferSize, language, posixSupport); self.resetRead(); self.setOK(true); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java index 5fd24560bf..d1bf1b29b2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -57,7 +57,7 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetClassNode.GetPythonObjectClassNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; +import com.oracle.graal.python.runtime.PosixSupport; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -115,16 +115,24 @@ static void doInit(VirtualFrame frame, @SuppressWarnings("unused") Node ignored, } public static void internalInit(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language, - Object posixSupport, - PosixSupportLibrary posixLib) { + PosixSupport posixSupport) { self.setDetached(false); self.setRaw(raw, true); - BufferedInitNode.internalInit(self, bufferSize, language, posixSupport, posixLib); + BufferedInitNode.internalInit(self, bufferSize, language, posixSupport); self.resetWrite(); self.setPos(0); self.setOK(true); } + + public static void internalInitConsole(PBuffered self, PFileIO raw, int bufferSize, PythonLanguage language) { + self.setDetached(false); + self.setRaw(raw, false); + BufferedInitNode.init(self, bufferSize, language); + self.resetWrite(); + self.setPos(0); + self.setOK(true); + } } // BufferedWriter(raw[, buffer_size=DEFAULT_BUFFER_SIZE]) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java index a182c5e772..baf270a634 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BufferedWriterNodes.java @@ -70,8 +70,7 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -237,7 +236,6 @@ abstract static class RawWriteNode extends PNodeWithContext { @Specialization(guards = "self.hasFileIORaw()") static int bufferedwriterRawWriteFileIO(VirtualFrame frame, Node inliningTarget, PBuffered self, byte[] buf, int len, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -252,7 +250,7 @@ static int bufferedwriterRawWriteFileIO(VirtualFrame frame, Node inliningTarget, final int n; try { n = Math.toIntExact(PosixModuleBuiltins.WriteNode.write(fileIO.getFD(), buf, len, - inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil)); + inliningTarget, context.getPosixSupport(), errorProfile, gil)); } catch (PosixException e) { if (e.hasErrno(OSErrorEnum.EAGAIN)) { return -2; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java index 5bc9da8838..c8e2b30493 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/BytesIOBuiltins.java @@ -133,6 +133,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PBytesIO) @@ -353,6 +354,7 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization(guards = "self.hasBuf()") static Object readlines(PBytesIO self, int maxsize, + @Bind Node inliningTarget, @Bind PythonLanguage language, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib) { ArrayBuilder result = new ArrayBuilder<>(); @@ -372,6 +374,7 @@ static Object readlines(PBytesIO self, int maxsize, } cur += n; } + LoopNode.reportLoopCount(inliningTarget, result.size()); return PFactory.createList(language, result.toArray(new Object[0])); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java new file mode 100644 index 0000000000..c2128c6f1f --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/CommonFileIOBuiltins.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 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 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.builtins.modules.io; + +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PFileIO; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PRawIOBase; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSED; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSEFD; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_FILENO; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_MODE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READABLE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITABLE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.T_CLOSE; +import static com.oracle.graal.python.nodes.ErrorMessages.IO_CLOSED; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + +import java.util.List; + +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins; +import com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins; +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.lib.PyErrChainExceptions; +import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; + +@CoreFunctions(extendClasses = {PFileIO, PWindowsConsoleIO}) +public final class CommonFileIOBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return CommonFileIOBuiltinsFactory.getFactories(); + } + + @Builtin(name = J_CLOSE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class CloseNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isCloseFD()") + static Object simple(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Exclusive @Cached PyObjectCallMethodObjArgs callClose) { + try { + callClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + self.setClosed(); + throw e; + } + self.setClosed(); + return PNone.NONE; + } + + @Specialization(guards = {"self.isCloseFD()", "!self.isFinalizing()"}) + static Object common(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, + @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, + @Shared @Cached PyErrChainExceptions chainExceptions) { + try { + callSuperClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + try { + FileIOBuiltins.internalClose(frame, self, posixClose); + } catch (PException ee) { + throw chainExceptions.execute(inliningTarget, ee, e); + } + throw e; + } + FileIOBuiltins.internalClose(frame, self, posixClose); + return PNone.NONE; + } + + @Specialization(guards = {"self.isCloseFD()", "self.isFinalizing()"}) + static Object slow(VirtualFrame frame, PFileIO self, + @Bind Node inliningTarget, + @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, + @Cached WarningsModuleBuiltins.WarnNode warnNode, + @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, + @Shared @Cached PyErrChainExceptions chainExceptions) { + PException rawIOException = null; + PythonContext context = PythonContext.get(inliningTarget); + try { + callSuperClose.execute(frame, inliningTarget, context.lookupType(PRawIOBase), T_CLOSE, self); + } catch (PException e) { + rawIOException = e; + } + FileIOBuiltins.deallocWarn(frame, self, warnNode); + try { + FileIOBuiltins.internalClose(frame, self, posixClose); + } catch (PException ee) { + if (rawIOException != null) { + throw chainExceptions.execute(inliningTarget, ee, rawIOException); + } else { + throw ee; + } + } + if (rawIOException != null) { + throw rawIOException; + } + return PNone.NONE; + } + } + + @Builtin(name = J_READABLE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class ReadableNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object readable(PFileIO self) { + return self.isReadable(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_WRITABLE, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class WritableNode extends PythonUnaryBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object writable(PFileIO self) { + return self.isWritable(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_FILENO, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class FilenoNode extends PythonBuiltinNode { + @Specialization(guards = "!self.isClosed()") + static Object fileno(PFileIO self) { + return self.getFD(); + } + + @Specialization(guards = "self.isClosed()") + static Object closedError(@SuppressWarnings("unused") PFileIO self, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + } + + @Builtin(name = J_CLOSED, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class ClosedNode extends PythonUnaryBuiltinNode { + @Specialization + static Object doit(PFileIO self) { + return self.getFD() < 0; + } + } + + @Builtin(name = J_CLOSEFD, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class CloseFDNode extends PythonUnaryBuiltinNode { + @Specialization + static Object doit(PFileIO self) { + return self.isCloseFD(); + } + } + + @Builtin(name = J_MODE, minNumOfPositionalArgs = 1, isGetter = true) + @GenerateNodeFactory + abstract static class ModeNode extends PythonUnaryBuiltinNode { + private static final TruffleString T_XB = tsLiteral("xb"); + private static final TruffleString T_XBP = tsLiteral("xb+"); + private static final TruffleString T_AB = tsLiteral("ab"); + private static final TruffleString T_ABP = tsLiteral("ab+"); + private static final TruffleString T_RB = tsLiteral("rb"); + private static final TruffleString T_RBP = tsLiteral("rb+"); + private static final TruffleString T_WB = tsLiteral("wb"); + + @Specialization + static TruffleString mode(PFileIO self) { + if (self.isCreated()) { + return self.isReadable() ? T_XBP : T_XB; + } + if (self.isAppending()) { + return self.isReadable() ? T_ABP : T_AB; + } else if (self.isReadable()) { + return self.isWritable() ? T_RBP : T_RB; + } + return T_WB; + } + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index b308aaf531..21fd8e5789 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -42,33 +42,24 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IOUnsupportedOperation; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError; -import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PRawIOBase; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.RuntimeError; import static com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.mapPythonSeekWhenceToPosix; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_CUR; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_END; import static com.oracle.graal.python.builtins.modules.io.IOBaseBuiltins.BUFSIZ; import static com.oracle.graal.python.builtins.modules.io.IOModuleBuiltins.DEFAULT_BUFFER_SIZE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSED; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_CLOSEFD; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_FILENO; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_ISATTY; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_MODE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READ; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READALL; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_READINTO; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_SEEK; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_SEEKABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_TELL; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_TRUNCATE; -import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITABLE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__BLKSIZE; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__DEALLOC_WARN; import static com.oracle.graal.python.builtins.modules.io.IONodes.J__FINALIZING; -import static com.oracle.graal.python.builtins.modules.io.IONodes.T_CLOSE; import static com.oracle.graal.python.builtins.modules.io.IONodes.T_NAME; import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.append; import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.createOutputStream; @@ -127,10 +118,8 @@ import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeNodes; -import com.oracle.graal.python.lib.PyErrChainExceptions; import com.oracle.graal.python.lib.PyIndexCheckNode; import com.oracle.graal.python.lib.PyNumberAsSizeNode; -import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; @@ -151,15 +140,14 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.ThreadLocalAction.Access; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; @@ -248,12 +236,12 @@ private static void errorCleanup(VirtualFrame frame, PFileIO self, boolean fdIsO private static int open(VirtualFrame frame, TruffleString name, int flags, int mode, PythonContext ctxt, Node inliningTarget, - PosixSupportLibrary posixLib, GilNode gil, + PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, InlinedBranchProfile errorProfile, PRaiseNode raiseNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - Object path = posixLib.createPathFromString(ctxt.getPosixSupport(), name); + Object path = createPathFromStringNode.execute(frame, inliningTarget, ctxt.getPosixSupport(), name); if (path == null) { throw raiseNode.raise(inliningTarget, ValueError, EMBEDDED_NULL_BYTE); } @@ -261,7 +249,7 @@ private static int open(VirtualFrame frame, TruffleString name, int flags, int m try { gil.release(true); try { - return posixLib.openat(ctxt.getPosixSupport(), AT_FDCWD.value, path, flags, mode); + return ctxt.getPosixSupport().openat(AT_FDCWD.value, path, flags, mode); } finally { gil.acquire(); } @@ -326,7 +314,6 @@ public static void internalInit(PFileIO self, TruffleString name, int fd, IOMode @Specialization(guards = {"!isBadMode(mode)", "!isInvalidMode(mode)"}) static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object nameobj, IONodes.IOMode mode, boolean closefd, Object opener, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached(inline = false) CallNode callOpener, @Cached PyIndexCheckNode indexCheckNode, @Cached PyNumberAsSizeNode asSizeNode, @@ -340,6 +327,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object @Cached InlinedBranchProfile exceptionProfile3, @Cached InlinedConditionProfile errorProfile, @Cached(inline = false) GilNode gil, + @Cached PosixSupportNodes.CreatePathFromStringNode createPathFromStringNode, @Cached TruffleString.FromLongNode fromLongNode, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -375,7 +363,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } if (opener instanceof PNone) { - self.setFD(open(frame, name, flags, 0666, context, inliningTarget, posixLib, gil, exceptionProfile, raiseNode, constructAndRaiseNode), context); + self.setFD(open(frame, name, flags, 0666, context, inliningTarget, gil, createPathFromStringNode, exceptionProfile, raiseNode, constructAndRaiseNode), context); } else { Object fdobj = callOpener.execute(frame, opener, nameobj, flags); if (!indexCheckNode.execute(inliningTarget, fdobj)) { @@ -392,7 +380,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } } try { - posixLib.setInheritable(context.getPosixSupport(), self.getFD(), false); + context.getPosixSupport().setInheritable(self.getFD(), false); } catch (PosixException e) { exceptionProfile1.enter(inliningTarget); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -404,7 +392,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object long[] fstatResult; gil.release(true); try { - fstatResult = posixLib.fstat(context.getPosixSupport(), self.getFD()); + fstatResult = context.getPosixSupport().fstat(self.getFD()); } finally { gil.acquire(); } @@ -412,7 +400,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object * On Unix, open will succeed for directories. In Python, there should be no * file objects referring to directories, so we need a check. */ - if (errorProfile.profile(inliningTarget, PosixSupportLibrary.isDIR(fstatResult[0]))) { + if (errorProfile.profile(inliningTarget, PosixSupport.isDIR(fstatResult[0]))) { errorCleanup(frame, self, fdIsOwn, posixClose); TruffleString fname = name == null ? fromLongNode.execute(fd, TS_ENCODING, false) : name; throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, OSErrorEnum.EISDIR, fname); @@ -442,7 +430,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object try { gil.release(true); try { - long res = posixLib.lseek(context.getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END)); + long res = context.getPosixSupport().lseek(self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_END)); self.setSeekable(res >= 0 ? 1 : 0); } finally { gil.acquire(); @@ -538,11 +526,10 @@ static Object read(VirtualFrame frame, PFileIO self, int size, @Cached InlinedBranchProfile readErrorProfile, @Cached InlinedBranchProfile readErrorProfile2, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + return PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); } catch (PosixException e) { if (e.hasErrno(EAGAIN)) { readErrorProfile2.enter(inliningTarget); @@ -575,7 +562,6 @@ static Object readall(VirtualFrame frame, PFileIO self, @Cached InlinedBranchProfile readErrorProfile, @Cached SequenceStorageNodes.GetInternalByteArrayNode getBytes, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile multipleReadsProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -584,8 +570,8 @@ static Object readall(VirtualFrame frame, PFileIO self, boolean mayBeQuick = false; try { PosixSupport posixSupport = PosixSupport.get(inliningTarget); - long pos = posixLib.lseek(posixSupport, self.getFD(), 0L, mapPythonSeekWhenceToPosix(SEEK_CUR)); - long[] status = posixLib.fstat(posixSupport, self.getFD()); + long pos = posixSupport.lseek(self.getFD(), 0L, mapPythonSeekWhenceToPosix(SEEK_CUR)); + long[] status = posixSupport.fstat(self.getFD()); long end = status[6]; // TODO: st_size if (end > 0 && end >= pos && pos >= 0 && end - pos < MAX_SIZE) { /* @@ -604,7 +590,7 @@ static Object readall(VirtualFrame frame, PFileIO self, int bytesRead = 0; PBytes b; try { - b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); bytesRead = b.getSequenceStorage().length(); if (bytesRead == 0 || (mayBeQuick && bytesRead == bufsize - 1)) { return b; @@ -632,7 +618,7 @@ static Object readall(VirtualFrame frame, PFileIO self, int n; try { - b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize - bytesRead, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + b = PosixModuleBuiltins.ReadNode.read(self.getFD(), bufsize - bytesRead, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); /* * PosixModuleBuiltins#ReadNode creates PBytes with exact size; */ @@ -677,7 +663,6 @@ static Object readinto(VirtualFrame frame, PFileIO self, Object buffer, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached InlinedBranchProfile readErrorProfile, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { @@ -686,7 +671,7 @@ static Object readinto(VirtualFrame frame, PFileIO self, Object buffer, return 0; } try { - PBytes data = PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, posixLib, context.getPosixSupport(), readErrorProfile, gil); + PBytes data = PosixModuleBuiltins.ReadNode.read(self.getFD(), size, inliningTarget, context.getPosixSupport(), readErrorProfile, gil); int n = bufferLib.getBufferLength(data); bufferLib.readIntoBuffer(data, 0, buffer, 0, n, bufferLib); return n; @@ -731,7 +716,6 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, @Bind Node inliningTarget, @Bind PythonContext context, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedBranchProfile errorProfile, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -745,7 +729,7 @@ static Object write(VirtualFrame frame, PFileIO self, Object buffer, } try { return PosixModuleBuiltins.WriteNode.write(self.getFD(), bufferLib.getInternalOrCopiedByteArray(buffer), bufferLib.getBufferLength(buffer), - inliningTarget, posixLib, context.getPosixSupport(), errorProfile, gil); + inliningTarget, context.getPosixSupport(), errorProfile, gil); } catch (PosixException e) { if (e.hasErrno(EAGAIN)) { return PNone.NONE; @@ -776,13 +760,12 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization(guards = "!self.isClosed()") Object seek(VirtualFrame frame, PFileIO self, long pos, int whence, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { gil.release(true); try { - return internalSeek(self, pos, whence, getPosixSupport(), posixLib); + return internalSeek(self, pos, whence, getPosixSupport()); } finally { gil.acquire(); } @@ -798,10 +781,9 @@ static Object closedError(@SuppressWarnings("unused") PFileIO self, @SuppressWar } protected static long internalSeek(PFileIO self, long pos, int whence, - Object posixSupport, - PosixSupportLibrary posixLib) throws PosixException { + PosixSupport posixSupport) throws PosixException { try { - long res = posixLib.lseek(posixSupport, self.getFD(), pos, mapPythonSeekWhenceToPosix(whence)); + long res = posixSupport.lseek(self.getFD(), pos, mapPythonSeekWhenceToPosix(whence)); if (self.getSeekable() < 0) { self.setSeekable(1); } @@ -824,9 +806,8 @@ static Object tell(VirtualFrame frame, PFileIO self, } static long internalTell(PFileIO self, - Object posixSupport, - PosixSupportLibrary posixLib) throws PosixException { - return SeekNode.internalSeek(self, 0, SEEK_CUR, posixSupport, posixLib); + PosixSupport posixSupport) throws PosixException { + return SeekNode.internalSeek(self, 0, SEEK_CUR, posixSupport); } } @@ -877,74 +858,6 @@ static Object closedError(PFileIO self, Object posobj, } } - @Builtin(name = J_CLOSE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class CloseNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isCloseFD()") - static Object simple(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Exclusive @Cached PyObjectCallMethodObjArgs callClose) { - try { - callClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - self.setClosed(); - throw e; - } - self.setClosed(); - return PNone.NONE; - } - - @Specialization(guards = {"self.isCloseFD()", "!self.isFinalizing()"}) - static Object common(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, - @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, - @Shared @Cached PyErrChainExceptions chainExceptions) { - try { - callSuperClose.execute(frame, inliningTarget, PythonContext.get(inliningTarget).lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - try { - internalClose(frame, self, posixClose); - } catch (PException ee) { - throw chainExceptions.execute(inliningTarget, ee, e); - } - throw e; - } - internalClose(frame, self, posixClose); - return PNone.NONE; - } - - @Specialization(guards = {"self.isCloseFD()", "self.isFinalizing()"}) - static Object slow(VirtualFrame frame, PFileIO self, - @Bind Node inliningTarget, - @Shared("c") @Cached PosixModuleBuiltins.CloseNode posixClose, - @Cached WarningsModuleBuiltins.WarnNode warnNode, - @Shared("l") @Cached PyObjectCallMethodObjArgs callSuperClose, - @Shared @Cached PyErrChainExceptions chainExceptions) { - PException rawIOException = null; - PythonContext context = PythonContext.get(inliningTarget); - try { - callSuperClose.execute(frame, inliningTarget, context.lookupType(PRawIOBase), T_CLOSE, self); - } catch (PException e) { - rawIOException = e; - } - deallocWarn(frame, self, warnNode); - try { - internalClose(frame, self, posixClose); - } catch (PException ee) { - if (rawIOException != null) { - throw chainExceptions.execute(inliningTarget, ee, rawIOException); - } else { - throw ee; - } - } - if (rawIOException != null) { - throw rawIOException; - } - return PNone.NONE; - } - } - @Builtin(name = J_SEEKABLE, minNumOfPositionalArgs = 1) @GenerateNodeFactory abstract static class SeekableNode extends PythonUnaryBuiltinNode { @@ -953,10 +866,9 @@ protected static boolean isUnknown(PFileIO self) { } @Specialization(guards = {"!self.isClosed()", "isUnknown(self)"}) - Object unknown(PFileIO self, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { + Object unknown(PFileIO self) { try { - posixLib.lseek(getPosixSupport(), self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_CUR)); + getPosixSupport().lseek(self.getFD(), 0, mapPythonSeekWhenceToPosix(SEEK_CUR)); self.setSeekable(1); return true; } catch (PosixException e) { @@ -978,61 +890,15 @@ static Object closedError(@SuppressWarnings("unused") PFileIO self, } } - @Builtin(name = J_READABLE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class ReadableNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object readable(PFileIO self) { - return self.isReadable(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - - @Builtin(name = J_WRITABLE, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class WritableNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object writable(PFileIO self) { - return self.isWritable(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - - @Builtin(name = J_FILENO, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - abstract static class FilenoNode extends PythonBuiltinNode { - @Specialization(guards = "!self.isClosed()") - static Object fileno(PFileIO self) { - return self.getFD(); - } - - @Specialization(guards = "self.isClosed()") - static Object closedError(@SuppressWarnings("unused") PFileIO self, - @Bind Node inliningTarget) { - throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); - } - } - @Builtin(name = J_ISATTY, minNumOfPositionalArgs = 1) @GenerateNodeFactory abstract static class IsattyNode extends PythonUnaryBuiltinNode { @Specialization(guards = "!self.isClosed()") boolean isatty(@SuppressWarnings("unused") PFileIO self, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil) { gil.release(true); try { - return posixLib.isatty(getPosixSupport(), self.getFD()); + return getPosixSupport().isatty(self.getFD()); } finally { gil.acquire(); } @@ -1056,54 +922,6 @@ static Object deallocWarn(VirtualFrame frame, PFileIO self, } } - @Builtin(name = J_CLOSED, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class ClosedNode extends PythonUnaryBuiltinNode { - @Specialization - static Object doit(PFileIO self) { - return self.getFD() < 0; - } - } - - @Builtin(name = J_CLOSEFD, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class CloseFDNode extends PythonUnaryBuiltinNode { - @Specialization - static Object doit(PFileIO self) { - return self.isCloseFD(); - } - } - - @Builtin(name = J_MODE, minNumOfPositionalArgs = 1, isGetter = true) - @GenerateNodeFactory - abstract static class ModeNode extends PythonUnaryBuiltinNode { - - public static final TruffleString T_XB = tsLiteral("xb"); - public static final TruffleString T_XBP = tsLiteral("xb+"); - public static final TruffleString T_AB = tsLiteral("ab"); - public static final TruffleString T_ABP = tsLiteral("ab+"); - public static final TruffleString T_RB = tsLiteral("rb"); - public static final TruffleString T_RBP = tsLiteral("rb+"); - public static final TruffleString T_WB = tsLiteral("wb"); - - static TruffleString modeString(PFileIO self) { - if (self.isCreated()) { - return self.isReadable() ? T_XBP : T_XB; - } - if (self.isAppending()) { - return self.isReadable() ? T_ABP : T_AB; - } else if (self.isReadable()) { - return self.isWritable() ? T_RBP : T_RB; - } - return T_WB; - } - - @Specialization - static TruffleString doit(PFileIO self) { - return modeString(self); - } - } - @Builtin(name = J__BLKSIZE, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true) @GenerateNodeFactory abstract static class BlksizeNode extends PythonBinaryBuiltinNode { @@ -1155,7 +973,7 @@ static TruffleString doit(VirtualFrame frame, PFileIO self, @Cached PyObjectReprAsTruffleStringNode repr, @Cached SimpleTruffleStringFormatNode simpleTruffleStringFormatNode, @Cached PRaiseNode raiseNode) { - TruffleString mode = ModeNode.modeString(self); + TruffleString mode = CommonFileIOBuiltins.ModeNode.mode(self); TruffleString closefd = self.isCloseFD() ? T_TRUE : T_FALSE; Object nameobj = lookupName.execute(frame, inliningTarget, self, T_NAME); if (nameobj instanceof PNone) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java index e248e10e62..ab1ae6299a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOBaseBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -136,6 +136,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -572,6 +573,7 @@ static Object withHint(VirtualFrame frame, Object self, int hintIn, } length += lineLength; } + LoopNode.reportLoopCount(inliningTarget, list.size()); return PFactory.createList(language, list.toArray(new Object[0])); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java index f963de8106..19c15ef504 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java @@ -93,7 +93,6 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; @@ -107,7 +106,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -206,7 +204,6 @@ protected static Object openText(VirtualFrame frame, Object file, IONodes.IOMode @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, @Cached TextIOWrapperNodes.TextIOWrapperInitNode initTextIO, @Cached PyObjectSetAttr setAttrNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Bind PythonLanguage language, @Exclusive @Cached PRaiseNode raiseNode) { @@ -218,7 +215,7 @@ protected static Object openText(VirtualFrame frame, Object file, IONodes.IOMode int buffering = bufferingValue; if (buffering < 0) { // copied from PFileIOBuiltins.IsAttyNode - isatty = posixLib.isatty(PosixSupport.get(inliningTarget), fileIO.getFD()); + isatty = PosixSupport.get(inliningTarget).isatty(fileIO.getFD()); /*- // CPython way is slow in our case. Object res = libFileIO.lookupAndCallRegularMethod(fileIO, frame, ISATTY); @@ -292,11 +289,10 @@ protected static Object openBinaryB1(VirtualFrame frame, Object file, IONodes.IO @Exclusive @Cached PyNumberCheckNode numberCheckNode, @Exclusive @Cached PyOSFSPathNode fsPathNode, @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Exclusive @Cached PRaiseNode raiseNode) { warnNode.warnEx(frame, RuntimeWarning, LINE_BUFFERING_ISNT_SUPPORTED, 1); - return openBinary(frame, file, mode, bufferingValue, encoding, errors, newline, closefd, opener, inliningTarget, initFileIO, numberCheckNode, fsPathNode, createBufferedIO, posixLib, + return openBinary(frame, file, mode, bufferingValue, encoding, errors, newline, closefd, opener, inliningTarget, initFileIO, numberCheckNode, fsPathNode, createBufferedIO, callClose, raiseNode); } @@ -311,7 +307,6 @@ protected static Object openBinary(VirtualFrame frame, Object file, IONodes.IOMo @Exclusive @Cached PyNumberCheckNode numberCheckNode, @Exclusive @Cached PyOSFSPathNode fsPathNode, @Exclusive @Cached IONodes.CreateBufferedIONode createBufferedIO, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Exclusive @Cached PyObjectCallMethodObjArgs callClose, @Exclusive @Cached PRaiseNode raiseNode) { PFileIO fileIO = createFileIOFromOpen(frame, inliningTarget, file, mode, closefd, opener, initFileIO, numberCheckNode, fsPathNode); @@ -321,7 +316,7 @@ protected static Object openBinary(VirtualFrame frame, Object file, IONodes.IOMo int buffering = bufferingValue; if (buffering < 0) { // copied from PFileIOBuiltins.IsAttyNode - isatty = posixLib.isatty(PosixSupport.get(inliningTarget), fileIO.getFD()); + isatty = PosixSupport.get(inliningTarget).isatty(fileIO.getFD()); /*- // CPython way is slow in our case. Object res = libFileIO.lookupAndCallRegularMethod(fileIO, frame, ISATTY); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java index f2ff239b55..41e3b9a33f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/PFileIO.java @@ -44,8 +44,7 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.AsyncHandler.SharedFinalizer.FinalizableReference; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.object.Shape; @@ -80,7 +79,6 @@ public int getFD() { } public void setFD(int fd, PythonContext context) { - assert this.fd == null : "'fd' has not been closed!"; if (closefd) { this.fd = new FD(fd, context); } else { @@ -213,7 +211,7 @@ void doRelease() { if (markReleased()) { assert isReleased(); try (GilNode.UncachedRelease gil = GilNode.uncachedRelease()) { - PosixSupportLibrary.getUncached().close(context.getPosixSupport(), (int) getReference()); + context.getPosixSupport().close((int) getReference()); } catch (PosixException e) { // ignore } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java new file mode 100644 index 0000000000..dcd8cef20e --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/WindowsConsoleIOBuiltins.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 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 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.builtins.modules.io; + +import static com.oracle.graal.python.annotations.PythonOS.PLATFORM_WIN32; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IOUnsupportedOperation; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_ISATTY; +import static com.oracle.graal.python.builtins.modules.io.IONodes.J_WRITE; +import static com.oracle.graal.python.builtins.modules.io.IONodes.T_NAME; +import static com.oracle.graal.python.nodes.ErrorMessages.CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING; +import static com.oracle.graal.python.nodes.ErrorMessages.CANNOT_OPEN_NON_CONSOLE_FILE; +import static com.oracle.graal.python.nodes.ErrorMessages.CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING; +import static com.oracle.graal.python.nodes.ErrorMessages.CONSOLE_INPUT_IS_NOT_SUPPORTED; +import static com.oracle.graal.python.nodes.ErrorMessages.IO_CLOSED; +import static com.oracle.graal.python.nodes.ErrorMessages.MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE; +import static com.oracle.graal.python.nodes.ErrorMessages.NEG_FILE_DESC; + +import java.util.List; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.ArgumentClinic; +import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.annotations.Slot; +import com.oracle.graal.python.annotations.Slot.SlotKind; +import com.oracle.graal.python.annotations.Slot.SlotSignature; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; +import com.oracle.graal.python.builtins.objects.type.TpSlots; +import com.oracle.graal.python.builtins.objects.type.TypeNodes; +import com.oracle.graal.python.nodes.PConstructAndRaiseNode; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + +@CoreFunctions(extendClasses = PWindowsConsoleIO, os = PLATFORM_WIN32) +public final class WindowsConsoleIOBuiltins extends PythonBuiltins { + private static final int CONSOLE_WRITE = 'w'; + public static final TpSlots SLOTS = WindowsConsoleIOBuiltinsSlotsGen.SLOTS; + + @Override + protected List> getNodeFactories() { + return WindowsConsoleIOBuiltinsFactory.getFactories(); + } + + public static PFileIO create(PythonLanguage language) { + return PFactory.createFileIO(PWindowsConsoleIO, PWindowsConsoleIO.getInstanceShape(language)); + } + + public static void internalInit(PFileIO self, Object name, int fd, IONodes.IOMode mode, int consoleType) { + if (mode.reading == mode.writing || mode.text || mode.universal || mode.isInvalid) { + throw PRaiseNode.raiseStatic(null, ValueError, MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE); + } + if (mode.reading) { + throw PRaiseNode.raiseStatic(null, ValueError, CONSOLE_INPUT_IS_NOT_SUPPORTED); + } + if (consoleType != CONSOLE_WRITE) { + throw PRaiseNode.raiseStatic(null, ValueError, CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING); + } + self.setCloseFD(false); + self.setFD(fd, null); + self.setWritable(); + self.setBlksize(IOModuleBuiltins.DEFAULT_BUFFER_SIZE); + WriteAttributeToObjectNode.getUncached().execute(self, T_NAME, name); + } + + @Slot(value = SlotKind.tp_new, isComplex = true) + @SlotSignature(name = "_WindowsConsoleIO", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) + @GenerateNodeFactory + abstract static class NewNode extends PythonBuiltinNode { + @Specialization + static PFileIO create(Object cls, @SuppressWarnings("unused") Object file, + @Cached TypeNodes.GetInstanceShape getInstanceShape) { + return PFactory.createFileIO(cls, getInstanceShape.execute(cls)); + } + } + + @Slot(value = SlotKind.tp_init, isComplex = true) + @SlotSignature(name = "_WindowsConsoleIO", minNumOfPositionalArgs = 2, parameterNames = {"$self", "file", "mode", "closefd", "opener"}) + @ArgumentClinic(name = "file", conversion = ArgumentClinic.ClinicConversion.Index) + @ArgumentClinic(name = "mode", conversionClass = IONodes.CreateIOModeNode.class, args = "false") + @ArgumentClinic(name = "closefd", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true", useDefaultForNone = true) + @GenerateNodeFactory + public abstract static class InitNode extends PythonClinicBuiltinNode { + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return WindowsConsoleIOBuiltinsClinicProviders.InitNodeClinicProviderGen.INSTANCE; + } + + @Specialization + static PNone init(PFileIO self, int file, IONodes.IOMode mode, @SuppressWarnings("unused") boolean closefd, @SuppressWarnings("unused") Object opener, + @Bind Node inliningTarget, + @Bind PythonContext context) { + if (file < 0) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, NEG_FILE_DESC); + } + // We don't release the GIL because CPython doesn't do it + int consoleType = context.getPosixSupport().getWindowsConsoleType(file); + if (consoleType == 0) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, CANNOT_OPEN_NON_CONSOLE_FILE); + } + internalInit(self, file, file, mode, consoleType); + return PNone.NONE; + } + } + + @Builtin(name = J_WRITE, minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 2, parameterNames = {"$self", "b"}) + @ArgumentClinic(name = "b", conversion = ArgumentClinic.ClinicConversion.ReadableBuffer) + @GenerateNodeFactory + abstract static class WriteNode extends PythonBinaryClinicBuiltinNode { + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return WindowsConsoleIOBuiltinsClinicProviders.WriteNodeClinicProviderGen.INSTANCE; + } + + @Specialization(limit = "3") + static Object write(VirtualFrame frame, PFileIO self, Object buffer, + @Bind Node inliningTarget, + @Bind PythonContext context, + @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, + @Cached GilNode gil, + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { + try { + if (self.isClosed()) { + throw PRaiseNode.raiseStatic(inliningTarget, ValueError, IO_CLOSED); + } + if (!self.isWritable()) { + throw PRaiseNode.raiseStatic(inliningTarget, IOUnsupportedOperation, CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING); + } + byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); + int length = bufferLib.getBufferLength(buffer); + try { + gil.release(true); + try { + return context.getPosixSupport().writeWindowsConsole(self.getFD(), new Buffer(bytes, length)); + } finally { + gil.acquire(); + } + } catch (PosixException e) { + throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); + } + } finally { + bufferLib.release(buffer); + } + } + } + + @Builtin(name = J_ISATTY, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + abstract static class IsattyNode extends PythonUnaryBuiltinNode { + @Specialization + static boolean isatty(PFileIO self, + @Bind Node inliningTarget, + @Cached PRaiseNode raise) { + if (self.isClosed()) { + throw raise.raise(inliningTarget, ValueError, IO_CLOSED); + } + return true; + } + } + +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java index 193609ad2b..742883b050 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/MultiprocessingModuleBuiltins.java @@ -60,8 +60,8 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -89,12 +89,11 @@ abstract static class Recv extends PythonBinaryClinicBuiltinNode { PBytes doit(VirtualFrame frame, int handle, int size, @Bind PythonContext context, @Bind PythonLanguage language, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] buffer = new byte[size]; try { - int received = posixLib.recv(context.getPosixSupport(), handle, buffer, 0, size, 0); + int received = context.getPosixSupport().recv(handle, buffer, 0, size, 0); if (received == size) { return PFactory.createBytes(language, buffer); } @@ -120,14 +119,13 @@ abstract static class Send extends PythonBinaryClinicBuiltinNode { @Specialization(limit = "3") static int doit(VirtualFrame frame, int handle, Object buffer, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("buffer") PythonBufferAccessLibrary bufferLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); - return posixLib.send(context.getPosixSupport(), handle, bytes, 0, bufferLib.getBufferLength(buffer), 0); + return context.getPosixSupport().send(handle, bytes, 0, bufferLib.getBufferLength(buffer), 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } finally { @@ -148,11 +146,10 @@ abstract static class CloseSocket extends PythonUnaryClinicBuiltinNode { @Specialization PNone doit(VirtualFrame frame, int handle, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.close(context.getPosixSupport(), handle); + context.getPosixSupport().close(handle); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -171,11 +168,11 @@ abstract static class SemUnlink extends PythonUnaryBuiltinNode { @Specialization PNone doit(VirtualFrame frame, TruffleString name, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Bind Node inliningTarget, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.semUnlink(posixSupport, posixLib.createCStringFromString(posixSupport, name)); + posixSupport.semUnlink(createCStringFromStringNode.execute(inliningTarget, posixSupport, name)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java index c730e88971..642c6ec633 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/multiprocessing/SemLockBuiltins.java @@ -77,9 +77,9 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -87,7 +87,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -120,26 +119,26 @@ abstract static class SemLockNode extends PythonClinicBuiltinNode { static PSemLock construct(VirtualFrame frame, Object cls, int kind, int value, int maxValue, TruffleString name, boolean unlink, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (kind != PSemLock.RECURSIVE_MUTEX && kind != PSemLock.SEMAPHORE) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.UNRECOGNIZED_KIND); } - Object posixName = posixLib.createCStringFromString(posixSupport, name); + Object posixName = createCStringFromStringNode.execute(inliningTarget, posixSupport, name); long handle; try { - handle = posixLib.semOpen(posixSupport, posixName, O_CREAT.value | O_EXCL.value, 0600, value); + handle = posixSupport.semOpen(posixName, O_CREAT.value | O_EXCL.value, 0600, value); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } if (unlink) { try { - posixLib.semUnlink(posixSupport, posixName); + posixSupport.semUnlink(posixName); } catch (PosixException e) { try { - posixLib.semClose(posixSupport, handle); + posixSupport.semClose(handle); } catch (PosixException ex) { // Ignore, we're already on an error path } @@ -201,7 +200,6 @@ abstract static class AcquireNode extends PythonTernaryClinicBuiltinNode { static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Object timeoutObj, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PyFloatAsDoubleNode asDoubleNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -223,7 +221,7 @@ static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Obje /* Check whether we can acquire without releasing the GIL and blocking */ boolean acquired; try { - acquired = posixLib.semTryWait(posixSupport, self.getHandle()); + acquired = posixSupport.semTryWait(self.getHandle()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -232,9 +230,9 @@ static boolean acquire(VirtualFrame frame, PSemLock self, boolean blocking, Obje gil.release(true); try { if (hasDeadline) { - acquired = posixLib.semTimedWait(posixSupport, self.getHandle(), deadlineNs); + acquired = posixSupport.semTimedWait(inliningTarget, self.getHandle(), deadlineNs); } else { - posixLib.semWait(posixSupport, self.getHandle()); + posixSupport.semWait(self.getHandle()); acquired = true; } } finally { @@ -266,7 +264,6 @@ abstract static class ReleaseNode extends PythonUnaryBuiltinNode { static PNone release(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (self.getKind() == PSemLock.RECURSIVE_MUTEX) { @@ -281,16 +278,16 @@ static PNone release(VirtualFrame frame, PSemLock self, int sval; try { try { - sval = posixLib.semGetValue(posixSupport, self.getHandle()); + sval = posixSupport.semGetValue(self.getHandle()); if (sval >= self.getMaxValue()) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SEMAPHORE_RELEASED_TOO_MANY_TIMES); } } catch (UnsupportedPosixFeatureException e) { /* We will only check properly the maxvalue == 1 case */ if (self.getMaxValue() == 1) { - if (posixLib.semTryWait(posixSupport, self.getHandle())) { + if (posixSupport.semTryWait(self.getHandle())) { /* it was not locked so undo wait and raise */ - posixLib.semPost(posixSupport, self.getHandle()); + posixSupport.semPost(self.getHandle()); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.SEMAPHORE_RELEASED_TOO_MANY_TIMES); } } @@ -300,7 +297,7 @@ static PNone release(VirtualFrame frame, PSemLock self, } } try { - posixLib.semPost(posixSupport, self.getHandle()); + posixSupport.semPost(self.getHandle()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -354,11 +351,10 @@ abstract static class GetValueNode extends PythonUnaryBuiltinNode { int get(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { - int sval = posixLib.semGetValue(posixSupport, self.getHandle()); + int sval = posixSupport.semGetValue(self.getHandle()); /* * some posix implementations use negative numbers to indicate the number of waiting * threads @@ -383,14 +379,13 @@ abstract static class IsZeroNode extends PythonUnaryBuiltinNode { static boolean get(VirtualFrame frame, PSemLock self, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { try { - return posixLib.semGetValue(posixSupport, self.getHandle()) == 0; + return posixSupport.semGetValue(self.getHandle()) == 0; } catch (UnsupportedPosixFeatureException e) { - if (posixLib.semTryWait(posixSupport, self.getHandle())) { - posixLib.semPost(posixSupport, self.getHandle()); + if (posixSupport.semTryWait(self.getHandle())) { + posixSupport.semPost(self.getHandle()); return false; } else { return true; @@ -422,17 +417,17 @@ abstract static class RebuildNode extends PythonClinicBuiltinNode { static Object rebuild(VirtualFrame frame, Object cls, long origHandle, int kind, int maxValue, Object name, @Bind Node inliningTarget, @Bind("getPosixSupport()") PosixSupport posixSupport, - @CachedLibrary("posixSupport") PosixSupportLibrary posixLib, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32) { return PFactory.createSemLock(cls, getInstanceShape.execute(cls), origHandle, kind, maxValue, null); } TruffleString posixNameString = (TruffleString) name; - Object posixName = posixLib.createCStringFromString(posixSupport, posixNameString); + Object posixName = createCStringFromStringNode.execute(inliningTarget, posixSupport, posixNameString); long handle; try { - handle = posixLib.semOpen(posixSupport, posixName); + handle = posixSupport.semOpen(posixName); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java deleted file mode 100644 index 34dd8b26cf..0000000000 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/ByteArrayView.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2024, 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 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.graal.python.builtins.modules.pickle; - -import com.oracle.graal.python.util.PythonUtils; - -public class ByteArrayView { - private final byte[] bytes; - private int offset; - - public ByteArrayView(byte[] bytes) { - this(bytes, 0); - } - - public ByteArrayView(byte[] bytes, int offset) { - this.bytes = bytes; - this.offset = offset; - validateOffset(0); - } - - private void validateOffset(int n) { - assert offset + n >= 0 && offset + n <= bytes.length; - } - - public void add(int n) { - validateOffset(n); - this.offset += n; - } - - public void sub(int n) { - this.add(-n); - } - - public byte[] getBytes(int len) { - assert len >= 0 && (len + offset) >= 0 && (len + offset) <= bytes.length; - if (offset == 0 && len == bytes.length) { - return bytes; - } - byte[] arr = new byte[len]; - PythonUtils.arraycopy(this.bytes, this.offset, arr, 0, len); - return arr; - } - - public int getOffset() { - return offset; - } - - public byte get(int i) { - return this.bytes[this.offset + i]; - } - - public int getUnsigned(int i) { - return get(i) & 0xff; - } - - public void put(int i, byte value) { - this.bytes[this.offset + i] = value; - } - - public void writeSize64(int value) { - PickleUtils.writeSize64(bytes, offset, value); - } - - public void memmove(int off, int num) { - PythonUtils.arraycopy(this.bytes, this.offset + off, this.bytes, this.offset, num); - } -} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java index 4393f54f42..182d4cdd95 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/MemoTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -42,6 +42,8 @@ import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; +import java.util.Arrays; + import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.util.PythonUtils; @@ -50,50 +52,22 @@ public final class MemoTable { - private static final int INITIAL_CAPACITY = 8; + static final int INITIAL_CAPACITY = 8; private static final int OCCUPANCY_EXPONENT = 1; // 2^X relation between capacity and size private static final int CAPACITY_INC_EXPONENT = 2; // 2^X increase in capacity when resizing - public static final class MemoIterator { - - private int index; - private final Object[] keys; - private final int[] values; - - public MemoIterator(MemoTable table) { - this.keys = table.keys; - this.values = table.values; - this.index = -1; - } - - public boolean advance() { - while (true) { - index++; - if (index >= keys.length) { - return false; - } - if (keys[index] != null) { - return true; - } - } - } - - public Object key() { - return keys[index]; - } - - public int value() { - return values[index]; - } - } - private Object[] keys; private int[] values; private int mask; private int size; public MemoTable() { - initArrays(INITIAL_CAPACITY); + this(INITIAL_CAPACITY); + } + + public MemoTable(int initialCapacity) { + assert initialCapacity >= INITIAL_CAPACITY && Integer.bitCount(initialCapacity) == 1; + initArrays(initialCapacity); } private MemoTable(MemoTable map) { @@ -112,7 +86,8 @@ public int size() { } public void clear() { - initArrays(INITIAL_CAPACITY); + Arrays.fill(keys, null); + Arrays.fill(values, 0); this.size = 0; } @@ -176,11 +151,20 @@ private void resize() { throw PRaiseNode.raiseStatic(null, PicklingError, ErrorMessages.STRUCT_SIZE_TOO_LONG); } - MemoIterator iterator = iterator(); // captures the current contents + Object[] oldKeys = keys; + int[] oldValues = values; initArrays(newLength); - while (iterator.advance()) { - setInternal(iterator.key(), iterator.value()); + for (int i = 0; i < oldKeys.length; i++) { + Object key = oldKeys[i]; + if (key != null) { + int index = getIndex(key); + while (keys[index] != null) { + index = (index + 1) & mask; + } + keys[index] = key; + values[index] = oldValues[i]; + } } } @@ -192,7 +176,15 @@ public void set(Object key, int value) { } } - public MemoIterator iterator() { - return new MemoIterator(this); + int capacity() { + return keys.length; + } + + Object getKeyAt(int index) { + return keys[index]; + } + + int getValueAt(int index) { + return values[index]; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java index de1e0508e8..68d31392b7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PPickler.java @@ -40,6 +40,12 @@ */ package com.oracle.graal.python.builtins.modules.pickle; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; +import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; +import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; +import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; +import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NEWOBJ_EX__; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NEWOBJ__; @@ -49,10 +55,7 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE_EX__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___REDUCE__; import static com.oracle.graal.python.nodes.StringLiterals.T_NEWLINE; -import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; -import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; -import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.PicklingError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; @@ -66,12 +69,16 @@ import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PNotImplemented; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAcquireLibrary; +import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; +import com.oracle.graal.python.builtins.objects.bytes.PByteArray; import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; import com.oracle.graal.python.builtins.objects.common.HashingStorage; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIterator; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageIteratorKey; @@ -80,53 +87,66 @@ import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageLen; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; -import com.oracle.graal.python.builtins.objects.ints.IntNodes; -import com.oracle.graal.python.builtins.objects.ints.IntNodesFactory; +import com.oracle.graal.python.builtins.objects.floats.PFloat; +import com.oracle.graal.python.builtins.objects.function.PFunction; +import com.oracle.graal.python.builtins.objects.ints.PInt; +import com.oracle.graal.python.builtins.objects.list.PList; import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.builtins.objects.set.PFrozenSet; import com.oracle.graal.python.builtins.objects.set.PSet; +import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; +import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.IteratorExhausted; import com.oracle.graal.python.lib.PyCallableCheckNode; -import com.oracle.graal.python.lib.PyFloatAsDoubleNode; import com.oracle.graal.python.lib.PyLongAsLongNode; import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectIsTrueNode; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; -import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.lib.PyObjectStrAsObjectNode; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.ErrorMessages; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.builtins.ListNodes; +import com.oracle.graal.python.nodes.builtins.TupleNodes.GetTupleStorage; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.IsNode; +import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; -import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage; +import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage; +import com.oracle.graal.python.runtime.sequence.storage.LongSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.graal.python.util.Consumer; import com.oracle.graal.python.util.NumericSupport; +import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.profiles.InlinedIntValueProfile; +import com.oracle.truffle.api.strings.TranscodingErrorHandler; import com.oracle.truffle.api.strings.TruffleString; public class PPickler extends PythonBuiltinObject { + private static final byte NEW_LINE_BYTE = '\n'; // Memo table, keep track of the seen objects to support self-referential objects pickling private MemoTable memo; // persistent_id() method, can be NULL @@ -144,8 +164,6 @@ public class PPickler extends PythonBuiltinObject { private byte[] outputBuffer; // Length of output_buffer private int outputLen; - // Allocation size of output_buffer - private int maxOutputLen; // Pickle protocol number, >= 0 private int proto; // true if proto > 0 @@ -162,11 +180,15 @@ public class PPickler extends PythonBuiltinObject { private int fastNesting; // Indicate whether Pickler should fix the name of globals for Python 2.x. private boolean fixImports; - private final Map fastMemo = createFastMemoTable(); + private Map fastMemo; // Callback for out-of-band buffers, or NULL private Object bufferCallback; public PPickler(Object cls, Shape instanceShape) { + this(cls, instanceShape, PickleUtils.WRITE_BUF_SIZE, MemoTable.INITIAL_CAPACITY); + } + + public PPickler(Object cls, Shape instanceShape, int outputCapacity, int memoCapacity) { super(cls, instanceShape); persFunc = null; dispatchTable = null; @@ -179,12 +201,11 @@ public PPickler(Object cls, Shape instanceShape) { fast = 0; fastNesting = 0; fixImports = false; - maxOutputLen = PickleUtils.WRITE_BUF_SIZE; outputLen = 0; reducerOverride = null; - memo = new MemoTable(); - outputBuffer = new byte[maxOutputLen]; + memo = new MemoTable(memoCapacity); + outputBuffer = new byte[outputCapacity]; } @TruffleBoundary @@ -240,6 +261,10 @@ public MemoTable getMemo() { return memo; } + public int getMaxOutputLen() { + return outputBuffer.length; + } + public void setMemo(MemoTable memo) { this.memo = memo; } @@ -260,18 +285,28 @@ public void setPersFuncSelf(Object persFuncSelf) { this.persFuncSelf = persFuncSelf; } + @TruffleBoundary + private void ensureFastMemo() { + if (fastMemo == null) { + fastMemo = createFastMemoTable(); + } + } + @TruffleBoundary private boolean fastMemoContains(Object object) { + ensureFastMemo(); return this.fastMemo.containsKey(object); } @TruffleBoundary private void fastMemoPut(Object object) { + ensureFastMemo(); this.fastMemo.put(object, true); } @TruffleBoundary private void fastMemoRemove(Object object) { + ensureFastMemo(); this.fastMemo.remove(object); } @@ -312,8 +347,7 @@ public void initInternals(VirtualFrame frame, Node inliningTarget, PyObjectLooku this.outputLen = 0; if (this.outputBuffer == null) { - this.maxOutputLen = PickleUtils.WRITE_BUF_SIZE; - this.outputBuffer = new byte[this.maxOutputLen]; + this.outputBuffer = new byte[PickleUtils.WRITE_BUF_SIZE]; } this.fast = 0; @@ -334,7 +368,6 @@ public void clearMemo() { } public void clearBuffer() { - this.outputBuffer = new byte[this.maxOutputLen]; this.outputLen = 0; this.frameStart = -1; } @@ -345,113 +378,382 @@ public void commitFrame() { } int frameLen = outputLen - frameStart - PickleUtils.FRAME_HEADER_SIZE; - ByteArrayView qdata = new ByteArrayView(outputBuffer, frameStart); if (frameLen >= PickleUtils.FRAME_SIZE_MIN) { - qdata.put(0, PickleUtils.OPCODE_FRAME); - qdata.add(1); - qdata.writeSize64(frameLen); + outputBuffer[frameStart] = PickleUtils.OPCODE_FRAME; + PickleUtils.writeSize64(outputBuffer, frameStart + 1, frameLen); } else { - qdata.memmove(PickleUtils.FRAME_HEADER_SIZE, frameLen); + PythonUtils.arraycopy(outputBuffer, frameStart + PickleUtils.FRAME_HEADER_SIZE, outputBuffer, frameStart, frameLen); outputLen -= PickleUtils.FRAME_HEADER_SIZE; } frameStart = -1; } - public PBytes getString(PythonLanguage language) { - commitFrame(); - return PFactory.createBytes(language, outputBuffer, outputLen); + public PBytes getString(PythonLanguage language, boolean copy) { + if (copy || outputBuffer.length > outputLen * 5 / 4) { + return PFactory.createBytes(language, PythonUtils.arrayCopyOf(outputBuffer, outputLen)); + } else { + return PFactory.createBytes(language, outputBuffer, outputLen); + } + } + + private void writeASCII(Node node, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.US_ASCII); + int length = encoded.byteLength(TruffleString.Encoding.US_ASCII); + ensureBufferSpace(node, length); + copyToByteArrayNode.execute(encoded, 0, outputBuffer, outputLen, length, TruffleString.Encoding.US_ASCII); + outputLen += length; + } + + private void writeUtf8(Node node, TruffleString string, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString encoded = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + writeUtf8Converted(node, encoded, copyToByteArrayNode); + } + + private void writeUtf8Converted(Node node, TruffleString encoded, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + int length = encoded.byteLength(TruffleString.Encoding.UTF_8); + ensureBufferSpace(node, length); + copyToByteArrayNode.execute(encoded, 0, outputBuffer, outputLen, length, TruffleString.Encoding.UTF_8); + outputLen += length; + } + + private void writeLongAsString(Node node, byte opcode, long value, TruffleString.FromLongNode fromLongNode, + TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString string = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); + TruffleString.Encoding encoding = TruffleString.Encoding.US_ASCII; + int length = string.byteLength(encoding); + ensureBufferSpace(node, length + 2); + outputBuffer[outputLen++] = opcode; + copyToByteArrayNode.execute(string, 0, outputBuffer, outputLen, length, encoding); + outputLen += length; + outputBuffer[outputLen++] = NEW_LINE_BYTE; + } + + private void write(Node node, byte b) { + ensureBufferSpace(node, 1); + outputBuffer[outputLen++] = b; + } + + private void write(Node node, byte b1, byte b2) { + ensureBufferSpace(node, 2); + outputBuffer[outputLen++] = b1; + outputBuffer[outputLen++] = b2; + } + + private void writeBuffer(Node node, Object buffer, int size, PythonBufferAccessLibrary bufferLib) { + ensureBufferSpace(node, size); + bufferLib.readIntoByteArray(buffer, 0, outputBuffer, outputLen, size); + outputLen += size; + } + + private void writeByteOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 2); + int start = outputLen; + outputBuffer[start] = opcode; + outputBuffer[start + 1] = (byte) value; + outputLen = start + 2; + } + + private void writeShortOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 3); + int start = outputLen; + outputBuffer[start] = opcode; + NumericSupport.littleEndian().putShort(outputBuffer, start + 1, (short) value); + outputLen = start + 3; + } + + private void writeIntOp(Node node, byte opcode, long value) { + ensureBufferSpace(node, 5); + int start = outputLen; + outputBuffer[start] = opcode; + NumericSupport.littleEndian().putInt(outputBuffer, start + 1, (int) value); + outputLen = start + 5; + } + + private void ensureBufferSpace(Node node, int dataLen) { + boolean needNewFrame = isFraming() && frameStart == -1; + int n = CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; + int required = outputLen + n; + + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, required > outputBuffer.length)) { + // Make place in buffer for the pickle chunk + // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, outputLen >= Integer.MAX_VALUE / 2 - n)) { + CompilerDirectives.transferToInterpreter(); + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); + } + int newCapacity = (required) / 2 * 3; + outputBuffer = PythonUtils.arrayCopyOf(outputBuffer, newCapacity); + } + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, needNewFrame)) { + frameStart = outputLen; + outputLen += PickleUtils.FRAME_HEADER_SIZE; + } + } + + private void writeRawUnicodeEscape(Node node, TruffleString string, + TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { + int codePointLength = codePointLengthNode.execute(string, TS_ENCODING); + long escapedLength = 0; + for (int i = 0; i < codePointLength; i++) { + int ch = codePointAtIndexNode.execute(string, i); + escapedLength += ch >= 0x10000 ? 10 : ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a ? 6 : 1; + } + if (escapedLength > Integer.MAX_VALUE) { + throw PRaiseNode.raiseStatic(node, PythonBuiltinClassType.MemoryError); + } + ensureBufferSpace(node, (int) escapedLength); + for (int i = 0; i < codePointLength; i++) { + int ch = codePointAtIndexNode.execute(string, i); + if (ch >= 0x10000) { + outputBuffer[outputLen++] = '\\'; + outputBuffer[outputLen++] = 'U'; + for (int shift = 28; shift >= 0; shift -= 4) { + outputBuffer[outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { + outputBuffer[outputLen++] = '\\'; + outputBuffer[outputLen++] = 'u'; + for (int shift = 12; shift >= 0; shift -= 4) { + outputBuffer[outputLen++] = BytesUtils.HEXDIGITS[(ch >> shift) & 0xf]; + } + } else { + outputBuffer[outputLen++] = (byte) ch; + } + } } // inner nodes - public abstract static class BasePickleWriteNode extends PicklerNodes.BasePickleNode { + @GenerateInline(false) + public abstract static class TupleStorageNode extends Node { + public abstract SequenceStorage execute(Object tuple); + + @Specialization + static SequenceStorage get(Object tuple, + @Bind Node inliningTarget, + @Cached GetTupleStorage getTupleStorage) { + return getTupleStorage.execute(inliningTarget, tuple); + } + } + + public abstract static class SaveNode extends PicklerNodes.BasePickleNode { + private static final int MAX_RECURSION_DEPTH = 3; + private static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); + static final byte[] TUPLE_LEN_2_OPCODE = new byte[]{PickleUtils.OPCODE_EMPTY_TUPLE, PickleUtils.OPCODE_TUPLE1, PickleUtils.OPCODE_TUPLE2, PickleUtils.OPCODE_TUPLE3}; - static final byte NEW_LINE_BYTE = '\n'; static final TruffleString DICT_ITEMS = tsLiteral("dict items"); static final TruffleString LATIN1 = tsLiteral("latin1"); - static final TruffleString REDUCE_OVERRIDE = tsLiteral("reducer_override"); static final TruffleString T_L_NEW_LINE = tsLiteral("L\n"); static final TruffleString T_SET = tsLiteral("set"); static final TruffleString T_DICTIONARY = tsLiteral("dictionary"); - @Child private IntNodes.PyLongSign pyLongSign; - @Child private IntNodes.PyLongNumBits pyLongNumBits; - @Child private IntNodes.PyLongAsByteArray pyLongAsByteArray; + private static final long SEEN_NONE = 1; + private static final long SEEN_BOOLEAN = 1 << 1; + private static final long SEEN_INTEGER = 1 << 2; + private static final long SEEN_LONG = 1 << 3; + private static final long SEEN_PINT = 1 << 4; + private static final long SEEN_DOUBLE = 1 << 5; + private static final long SEEN_PFLOAT = 1 << 6; + private static final long SEEN_BUILTIN_CLASS_TYPE = 1 << 7; + private static final long SEEN_BYTES = 1 << 8; + private static final long SEEN_TRUFFLE_STRING = 1 << 9; + private static final long SEEN_PSTRING = 1 << 10; + private static final long SEEN_DICT = 1 << 11; + private static final long SEEN_SET = 1 << 12; + private static final long SEEN_FROZENSET = 1 << 13; + private static final long SEEN_LIST = 1 << 14; + private static final long SEEN_TUPLE = 1 << 15; + private static final long SEEN_NATIVE_TUPLE = 1 << 16; + private static final long SEEN_BYTE_ARRAY = 1 << 17; + private static final long SEEN_PICKLE_BUFFER = 1 << 18; + private static final long SEEN_MANAGED_CLASS = 1 << 19; + private static final long SEEN_NATIVE_CLASS = 1 << 20; + private static final long SEEN_FUNCTION = 1 << 21; + private static final long SEEN_TYPE = 1 << 22; + private static final long SEEN_OBJECT = 1 << 23; + private static final long SEEN_INT_STORAGE = 1 << 24; + private static final long SEEN_LONG_STORAGE = 1 << 25; + private static final long SEEN_DOUBLE_STORAGE = 1 << 26; + private static final long SEEN_GENERIC_STORAGE = 1 << 27; + private static final long SEEN_CUSTOM_DISPATCH = 1 << 28; + private static final long SEEN_REGISTERED_REDUCER = 1 << 29; + private static final long SEEN_REDUCE_EX = 1 << 30; + private static final long SEEN_REDUCE = 1L << 31; + private static final long SEEN_NEWOBJ_EX = 1L << 32; + private static final long SEEN_NEWOBJ = 1L << 33; + private static final long SEEN_PLAIN_REDUCE = 1L << 34; + private static final long SEEN_REDUCE_LISTITEMS = 1L << 35; + private static final long SEEN_REDUCE_DICTITEMS = 1L << 36; + private static final long SEEN_REDUCE_STATE = 1L << 37; + private static final long SEEN_BYPASS_BUFFER = 1L << 38; + + @CompilationFinal private long seenTypes; + + private final int depth; + // Keep recursive profiles separate for each role in the pickle stream. + @Child private SaveNode dictKeySaveNode; + @Child private SaveNode dictValueSaveNode; + @Child private SaveNode setElementSaveNode; + @Child private SaveNode listElementSaveNode; + @Child private SaveNode tupleElementSaveNode; + @Child private SaveNode persistentIdSaveNode; + @Child private SaveNode reduceClassSaveNode; + @Child private SaveNode reduceCallableSaveNode; + @Child private SaveNode reduceArgsSaveNode; + @Child private SaveNode reduceKwargsSaveNode; + @Child private SaveNode reduceStateSaveNode; + @Child private SaveNode reduceStateSetterSaveNode; + @Child private SaveNode reduceObjectSaveNode; + @Child private SaveNode globalModuleNameSaveNode; + @Child private SaveNode globalNameSaveNode; + @Child private ListNodes.ConstructListNode constructListNode; - @Child private IsSubtypeNode isSubTypeNode; @Child private TypeNodes.IsTypeNode isTypeNode; @Child private FlushToFileNode flushToFileNode; - @Child private CallNode callNode; + @Child private TupleStorageNode getTupleStorageNode; + @Child private TruffleString.CodePointAtIndexUTF32Node tsCodePointAtIndexUTF32Node; + @Child private TruffleString.FromLongNode tsFromLongNode; + @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; + @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; + @Child private BoundaryCallData boundaryCallData; + @Child private PyLongAsLongNode pyLongAsLongNode; + @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; + @Child private PyObjectIsTrueNode isTrueNode; + @Child private IsNode isNode; + @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; + @Child private PythonBufferAccessLibrary bufferLibrary; + @Child private PyCallableCheckNode callableCheckNode; + @Child private PyObjectReprAsTruffleStringNode reprNode; + @Child private PyObjectGetIter getIterNode; + @Child private HashingStorageLen hashingStorageLenNode; + @Child private PyTupleCheckNode.CachedNode tupleCheckNode; - protected boolean isType(Object obj) { - if (isTypeNode == null) { + protected SaveNode(int depth) { + this.depth = depth; + } + + protected SequenceStorage getTupleStorage(Object tuple) { + if (getTupleStorageNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - isTypeNode = insert(TypeNodes.IsTypeNode.create()); + getTupleStorageNode = insert(PPicklerFactory.TupleStorageNodeGen.create()); } - return isTypeNode.executeCached(obj); + return getTupleStorageNode.execute(tuple); } - protected void flushToFile(VirtualFrame frame, PPickler pickler) { - if (flushToFileNode == null) { + protected TruffleString.CodePointAtIndexUTF32Node ensureTsCodePointAtIndexUTF32Node() { + if (tsCodePointAtIndexUTF32Node == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - flushToFileNode = insert(PPicklerFactory.FlushToFileNodeGen.create()); + tsCodePointAtIndexUTF32Node = insert(TruffleString.CodePointAtIndexUTF32Node.create()); } - flushToFileNode.execute(frame, pickler); + return tsCodePointAtIndexUTF32Node; } - protected int getSign(Object value) { - if (pyLongSign == null) { + protected TruffleString.FromLongNode ensureTsFromLongNode() { + if (tsFromLongNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongSign = insert(IntNodesFactory.PyLongSignNodeGen.create()); + tsFromLongNode = insert(TruffleString.FromLongNode.create()); } - return pyLongSign.execute(value); + return tsFromLongNode; } - protected int getNumBits(Object value) { - if (pyLongNumBits == null) { + protected TruffleString.CopyToByteArrayNode ensureTsCopyToByteArrayNode() { + if (tsCopyToByteArrayNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongNumBits = insert(IntNodesFactory.PyLongNumBitsNodeGen.create()); + tsCopyToByteArrayNode = insert(TruffleString.CopyToByteArrayNode.create()); } - return pyLongNumBits.execute(value); + return tsCopyToByteArrayNode; } - protected byte[] longAsBytes(Object value, int size, boolean bigEndian) { - if (pyLongAsByteArray == null) { + protected TruffleString.GetCodeRangeNode ensureTsGetCodeRangeNode() { + if (tsGetCodeRangeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - pyLongAsByteArray = insert(IntNodesFactory.PyLongAsByteArrayNodeGen.create()); + tsGetCodeRangeNode = insert(TruffleString.GetCodeRangeNode.create()); } - return pyLongAsByteArray.executeCached(value, size, bigEndian); + return tsGetCodeRangeNode; } - protected Object createList(VirtualFrame frame, Object iterable) { - if (constructListNode == null) { + public TruffleString asStringStrict(Object value) { + TruffleString string = asString(value); + if (string == null) { + throw raise(TypeError, MUST_BE_STR_NOT_P, value); + } + return string; + } + + private static boolean checkModule(VirtualFrame frame, PicklerNodes.LookupGlobalAttributeNode lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { + if (module == PNone.NONE) { + return false; + } + assert !(moduleName instanceof String) : "moduleName shouldn't be j.l.String"; + if (moduleName instanceof TruffleString && ((TruffleString) moduleName).equalsUncached(T___MAIN__, TS_ENCODING)) { + return false; + } + Pair pair = getDeepAttribute(frame, lookup, module, dottedPath); + return pair != null && pair.getLeft() == global; + } + + public TruffleString whichModule(VirtualFrame frame, PythonContext context, Object global, TruffleString[] dottedPath) { + Object moduleName = lookupAttribute(frame, global, T___MODULE__); + if (moduleName != NO_VALUE && moduleName != PNone.NONE) { + return asStringStrict(moduleName); + } + + PDict sysModules = context.getSysModules(); + if (sysModules == null) { + throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.UNABLE_TO_GET_S, T_SYS_MODULES); + } + + HashingStorage storage = sysModules.getDictStorage(); + HashingStorageIterator it = getHashingStorageIterator(storage); + HashingStorageIteratorNext nextNode = ensureHashingStorageIteratorNext(); + HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); + HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); + while (nextNode.executeCached(storage, it)) { + Object value = getValueNode.executeCached(storage, it); + Object key = getKeyNode.executeCached(storage, it); + if (checkModule(frame, getLookupGlobalAttrNode(), moduleName, value, global, dottedPath)) { + return asStringStrict(key); + } + } + return T___MAIN__; + } + + protected boolean isType(Object obj) { + if (isTypeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - constructListNode = insert(ListNodes.ConstructListNode.create()); + isTypeNode = insert(TypeNodes.IsTypeNode.create()); } - return constructListNode.execute(frame, iterable); + return isTypeNode.executeCached(obj); } - protected boolean isSubType(Object clsA, Object clsB) { - if (isSubTypeNode == null) { + protected void flushToFile(VirtualFrame frame, PPickler pickler) { + ensureFlushToFileNode().execute(frame, pickler); + } + + protected FlushToFileNode ensureFlushToFileNode() { + if (flushToFileNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - isSubTypeNode = insert(IsSubtypeNode.create()); + flushToFileNode = insert(PPicklerFactory.FlushToFileNodeGen.create()); } - return isSubTypeNode.execute(clsA, clsB); + return flushToFileNode; } - protected CallNode getCallNode() { - if (callNode == null) { + protected Object createList(VirtualFrame frame, Object iterable) { + if (constructListNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - callNode = insert(CallNode.create()); + constructListNode = insert(ListNodes.ConstructListNode.create()); } - return callNode; + return constructListNode.execute(frame, iterable); } - public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { + public boolean opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (!pickler.isFraming() || pickler.frameStart == -1) { - return; + return false; } int frameLen = pickler.outputLen - pickler.frameStart - PickleUtils.FRAME_HEADER_SIZE; - if (frameLen >= PickleUtils.FRAME_SIZE_TARGET) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, frameLen >= PickleUtils.FRAME_SIZE_TARGET)) { pickler.commitFrame(); // Flush the content of the committed frame to the underlying // file and reuse the pickler buffer for the next frame so as @@ -460,8 +762,10 @@ public void opcodeBoundary(VirtualFrame frame, PPickler pickler) { if (pickler.write != null) { flushToFile(frame, pickler); pickler.clearBuffer(); + return true; } } + return false; } public static void handleError(PPickler pickler) { @@ -469,82 +773,6 @@ public static void handleError(PPickler pickler) { pickler.reducerOverride = null; } - protected void writeASCII(PPickler pickler, TruffleString string) { - assert string.getCodeRangeUncached(TS_ENCODING) == TruffleString.CodeRange.ASCII; - final byte[] bytes = PythonUtils.getAsciiBytes(string, ensureTsCopyToByteArrayNode(), ensureTsSwitchEncodingNode()); - write(pickler, bytes, bytes.length); - } - - protected void write(PPickler pickler, byte oneByte) { - write(pickler, new byte[]{oneByte}, 1); - } - - protected void write(PPickler pickler, byte[] bytes) { - write(pickler, bytes, bytes.length); - } - - protected void write(PPickler pickler, byte[] bytes, int dataLen) { - boolean needNewFrame = pickler.isFraming() && pickler.frameStart == -1; - int n = (needNewFrame) ? dataLen + PickleUtils.FRAME_HEADER_SIZE : dataLen; - int required = pickler.outputLen + n; - - if (required > pickler.maxOutputLen) { - // Make place in buffer for the pickle chunk - // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX - if (pickler.outputLen >= Integer.MAX_VALUE / 2 - n) { - throw raise(PythonBuiltinClassType.MemoryError); - } - pickler.maxOutputLen = (pickler.outputLen + n) / 2 * 3; - pickler.outputBuffer = PickleUtils.resize(pickler.outputBuffer, pickler.maxOutputLen); - } - if (needNewFrame) { - int frameStart = pickler.outputLen; - pickler.frameStart = frameStart; - for (int i = 0; i < PickleUtils.FRAME_HEADER_SIZE; i++) { - // Write an invalid value, for debugging - pickler.outputBuffer[frameStart + i] = (byte) 0xFE; - } - pickler.outputLen += PickleUtils.FRAME_HEADER_SIZE; - } - PythonUtils.arraycopy(bytes, 0, pickler.outputBuffer, pickler.outputLen, dataLen); - pickler.outputLen += dataLen; - } - - protected void writeBytes(VirtualFrame frame, PPickler pickler, byte[] header, int headerSize, byte[] data, int dataSize, Object payload) { - boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; - boolean framing = pickler.framing; - - if (bypassBuffer) { - assert pickler.outputBuffer != null; - // Commit the previous frame. - pickler.commitFrame(); - // Disable framing temporarily - pickler.framing = false; - } - - write(pickler, header, headerSize); - - if (bypassBuffer && pickler.write != null) { - // Dump the output buffer to the file. - flushToFile(frame, pickler); - // Stream write the payload into the file without going through the output buffer. - Object pld = payload; - if (pld == null) { - // TODO: It would be better to use a memoryview with a linked original string if - // this is possible. - pld = PFactory.createBytes(PythonLanguage.get(this), data, dataSize); - } - getCallNode().execute(frame, pickler.write, pld); - // Reinitialize the buffer for subsequent calls to _Pickler_Write. - pickler.clearBuffer(); - } else { - write(pickler, data, dataSize); - } - - // Re-enable framing for subsequent calls to _Pickler_Write. - pickler.framing = framing; - } - protected PTuple createTuple(Object... items) { if (items.length == 0) { return PFactory.createEmptyTuple(PythonLanguage.get(this)); @@ -568,34 +796,33 @@ protected static void fastSaveLeave(PPickler pickler, Object obj) { pickler.fastMemoRemove(obj); } } - } - public abstract static class FlushToFileNode extends BasePickleWriteNode { - public abstract void execute(VirtualFrame frame, PPickler pickler); + private void profileSeen(long seen) { + if ((seenTypes & seen) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenTypes |= seen; + } + } - @Specialization - public void flush(VirtualFrame frame, PPickler pickler, - @Bind PythonLanguage language) { - assert pickler.write != null; - // This will commit the frame first - PBytes output = pickler.getString(language); - call(frame, pickler.write, output); + private boolean bypassBuffer(PPickler pickler, int dataSize) { + boolean bypassBuffer = dataSize >= PickleUtils.FRAME_SIZE_TARGET; + if (bypassBuffer) { + profileSeen(SEEN_BYPASS_BUFFER); + assert pickler.outputBuffer != null; + // Commit the previous frame before disabling framing temporarily. + pickler.commitFrame(); + pickler.framing = false; + } + return bypassBuffer; } - } - public abstract static class SaveNode extends BasePickleWriteNode { - @Child private SaveNode recursiveSaveNode; - @Child private PyLongAsLongNode pyLongAsLongNode; - @Child private PyObjectStrAsObjectNode pyObjectStrAsObjectNode; - @Child private PyObjectIsTrueNode isTrueNode; - @Child private IsNode isNode; - @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; - @Child private PythonBufferAccessLibrary bufferLibrary; - @Child private PyCallableCheckNode callableCheckNode; - @Child private PyObjectReprAsTruffleStringNode reprNode; - @Child private PyObjectGetIter getIterNode; - @Child private HashingStorageLen hashingStorageLenNode; - @Child private PyTupleCheckNode.CachedNode tupleCheckNode; + private BoundaryCallData getBoundaryCallData() { + if (boundaryCallData == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + boundaryCallData = insert(BoundaryCallData.createFor(this)); + } + return boundaryCallData; + } private int getHashingStorageLength(HashingStorage storage) { if (hashingStorageLenNode == null) { @@ -613,12 +840,204 @@ private boolean isTuple(Object object) { return tupleCheckNode.execute(object); } - private void save(VirtualFrame frame, PPickler pickler, Object obj, int persSave) { - if (recursiveSaveNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveSaveNode = insert(PPicklerFactory.SaveNodeGen.create()); + private void saveDictKey(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (dictKeySaveNode == null) { + dictKeySaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, dictKeySaveNode, pickler, obj, 0); + } + + private void saveDictValue(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (dictValueSaveNode == null) { + dictValueSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, dictValueSaveNode, pickler, obj, 0); + } + + private void saveSetElement(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (setElementSaveNode == null) { + setElementSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, setElementSaveNode, pickler, obj, 0); + } + + private void saveListElement(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (listElementSaveNode == null) { + listElementSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, listElementSaveNode, pickler, obj, 0); + } + + private void saveTupleElement(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (tupleElementSaveNode == null) { + tupleElementSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, tupleElementSaveNode, pickler, obj, 0); + } + + private void savePersistentId(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 1); + return; + } + if (persistentIdSaveNode == null) { + persistentIdSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, persistentIdSaveNode, pickler, obj, 1); + } + + private void saveReduceClass(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceClassSaveNode == null) { + reduceClassSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceClassSaveNode, pickler, obj, 0); + } + + private void saveReduceCallable(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceCallableSaveNode == null) { + reduceCallableSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceCallableSaveNode, pickler, obj, 0); + } + + private void saveReduceArgs(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceArgsSaveNode == null) { + reduceArgsSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceArgsSaveNode, pickler, obj, 0); + } + + private void saveReduceKwargs(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceKwargsSaveNode == null) { + reduceKwargsSaveNode = createRecursiveSaveNode(); } - recursiveSaveNode.execute(frame, pickler, obj, persSave); + saveRecursive(frame, reduceKwargsSaveNode, pickler, obj, 0); + } + + private void saveReduceState(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceStateSaveNode == null) { + reduceStateSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceStateSaveNode, pickler, obj, 0); + } + + private void saveReduceStateSetter(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceStateSetterSaveNode == null) { + reduceStateSetterSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceStateSetterSaveNode, pickler, obj, 0); + } + + private void saveReduceObject(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (reduceObjectSaveNode == null) { + reduceObjectSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, reduceObjectSaveNode, pickler, obj, 0); + } + + private void saveGlobalModuleName(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (globalModuleNameSaveNode == null) { + globalModuleNameSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, globalModuleNameSaveNode, pickler, obj, 0); + } + + private void saveGlobalName(VirtualFrame frame, PPickler pickler, Object obj) { + if (depth < 0) { + saveDepthExceeded(pickler, obj, 0); + return; + } + if (globalNameSaveNode == null) { + globalNameSaveNode = createRecursiveSaveNode(); + } + saveRecursive(frame, globalNameSaveNode, pickler, obj, 0); + } + + private SaveNode createRecursiveSaveNode() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + return insert(PPicklerFactory.SaveNodeGen.create(depth < MAX_RECURSION_DEPTH ? depth + 1 : -1)); + } + + private void saveRecursive(VirtualFrame frame, SaveNode saveNode, PPickler pickler, Object obj, int persSave) { + if (depth < MAX_RECURSION_DEPTH) { + saveNode.execute(frame, pickler, obj, persSave); + } else { + saveSetupBoundary(frame, saveNode, pickler, obj, persSave); + } + } + + // This should never be reached for compilation, but native-image can't prove it at build time + @TruffleBoundary + private void saveDepthExceeded(PPickler pickler, Object obj, int persSave) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + execute(null, pickler, obj, persSave); + } + + private void saveSetupBoundary(VirtualFrame frame, SaveNode saveNode, PPickler pickler, Object obj, int persSave) { + BoundaryCallData callData = getBoundaryCallData(); + Object savedState = BoundaryCallContext.enter(frame, callData); + try { + saveBoundary(saveNode, pickler, obj, persSave); + } finally { + BoundaryCallContext.exit(frame, callData, savedState); + } + } + + @TruffleBoundary + private void saveBoundary(SaveNode saveNode, PPickler pickler, Object obj, int persSave) { + saveNode.execute(null, pickler, obj, persSave); } private long asLong(VirtualFrame frame, Object object) { @@ -695,6 +1114,10 @@ private PythonBufferAccessLibrary getBufferLibrary() { public abstract void execute(VirtualFrame frame, PPickler pickler, Object obj, int persSave); + private static boolean isBin(int proto) { + return proto > 0; + } + // collections private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, HashingStorage storage, byte opcodeBatch, TruffleString name, boolean saveValues) { @@ -709,17 +1132,20 @@ private void saveHashingStorageBatched(VirtualFrame frame, PPickler pickler, Has int i; do { i = 0; - write(pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); while (nextNode.executeCached(storage, it)) { - save(frame, pickler, getKeyNode.executeCached(storage, it), 0); + Object key = getKeyNode.executeCached(storage, it); if (saveValues) { - save(frame, pickler, getValueNode.executeCached(storage, it), 0); + saveDictKey(frame, pickler, key); + saveDictValue(frame, pickler, getValueNode.executeCached(storage, it)); + } else { + saveSetElement(frame, pickler, key); } if (++i == PickleUtils.BATCHSIZE) { break; } } - write(pickler, opcodeBatch); + pickler.write(this, opcodeBatch); if (getHashingStorageLength(storage) != initialSize) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CHANGED_SIZE_DURING_ITERATION, name); } @@ -740,7 +1166,7 @@ private void saveSetHashingStorage(VirtualFrame frame, PPickler pickler, Hashing HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); while (next.executeCached(storage, it)) { Object item = getKeyNode.executeCached(storage, it); - save(frame, pickler, item, 0); + saveSetElement(frame, pickler, item); } } @@ -765,12 +1191,12 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O } catch (IteratorExhausted e) { // Only one item to write saveItem.accept(firstItem); - write(pickler, opcodeOneItem); + pickler.write(this, opcodeOneItem); break; } // More than one item to write // Pump out MARK, items, APPENDS. - write(pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); saveItem.accept(firstItem); n = 1; while (true) { @@ -789,7 +1215,7 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O break; } } - write(pickler, opcodeMultipleItems); + pickler.write(this, opcodeMultipleItems); } while (n == PickleUtils.BATCHSIZE); } @@ -797,13 +1223,14 @@ private void saveIteratorBatchedUnrolled(VirtualFrame frame, PPickler pickler, O private void saveDictIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, Object iterator) { saveIteratorBatchedUnrolled(frame, pickler, iterator, PickleUtils.OPCODE_SETITEM, PickleUtils.OPCODE_SETITEMS, (Object item) -> { - if (!isTuple(item) || length(frame, item) != 2) { + if (!isTuple(item) || getTupleStorage(item).length() != 2) { throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } }, (Object item) -> { - save(frame, pickler, getItem(frame, item, 0), 0); - save(frame, pickler, getItem(frame, item, 1), 0); + SequenceStorage storage = getTupleStorage(item); + saveDictKey(frame, pickler, getItem(storage, 0)); + saveDictValue(frame, pickler, getItem(storage, 1)); }); } @@ -811,7 +1238,7 @@ private void saveListIteratorBatchUnrolled(VirtualFrame frame, PPickler pickler, saveIteratorBatchedUnrolled(frame, pickler, iterator, PickleUtils.OPCODE_APPEND, PickleUtils.OPCODE_APPENDS, (Object item) -> { }, - (Object item) -> save(frame, pickler, item, 0)); + (Object item) -> saveListElement(frame, pickler, item)); } private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, byte opcode, Consumer itemConsumer) { @@ -824,54 +1251,50 @@ private void saveIterator(VirtualFrame frame, PPickler pickler, Object iterator, } itemConsumer.accept(item); if (opcode != PickleUtils.NO_OPCODE) { - write(pickler, opcode); + pickler.write(this, opcode); } } } private void saveListIterator(VirtualFrame frame, PPickler pickler, Object iterator) { saveIterator(frame, pickler, iterator, PickleUtils.OPCODE_APPEND, - (Object item) -> save(frame, pickler, item, 0)); - } - - private void saveFrozenSetIterator(VirtualFrame frame, PPickler pickler, Object iterator) { - saveIterator(frame, pickler, iterator, PickleUtils.NO_OPCODE, - (Object item) -> save(frame, pickler, item, 0)); + (Object item) -> saveListElement(frame, pickler, item)); } private void saveDictIterator(VirtualFrame frame, PPickler pickler, Object iterator) { saveIterator(frame, pickler, iterator, PickleUtils.OPCODE_SETITEM, (Object item) -> { - if (!isTuple(item) || length(frame, item) != 2) { + if (!isTuple(item) || getTupleStorage(item).length() != 2) { throw raise(TypeError, ErrorMessages.MUST_S_ITER_RETURN_2TUPLE, DICT_ITEMS); } - save(frame, pickler, getItem(frame, item, 0), 0); - save(frame, pickler, getItem(frame, item, 1), 0); + SequenceStorage storage = getTupleStorage(item); + saveDictKey(frame, pickler, getItem(storage, 0)); + saveDictValue(frame, pickler, getItem(storage, 1)); }); } // save methods - private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { + private boolean savePers(VirtualFrame frame, PPickler pickler, int proto, Object obj) { Object pid; if (pickler.persFuncSelf == null) { - pid = getCallNode().execute(frame, pickler.persFunc, obj); + pid = ensureCallNode().execute(frame, pickler.persFunc, obj); } else { - pid = getCallNode().execute(frame, pickler.persFunc, pickler.persFuncSelf, obj); + pid = ensureCallNode().execute(frame, pickler.persFunc, pickler.persFuncSelf, obj); } if (pid != PNone.NONE) { - if (pickler.isBin()) { - save(frame, pickler, pid, 1); - write(pickler, PickleUtils.OPCODE_BINPERSID); + if (isBin(proto)) { + savePersistentId(frame, pickler, pid); + pickler.write(this, PickleUtils.OPCODE_BINPERSID); } else { final TruffleString pidStr = asString(convertToStr(frame, pid)); // XXX: Should it check whether the pid contains embedded newlines? if (!PythonUtils.isAscii(pidStr, ensureTsGetCodeRangeNode())) { throw raise(PythonBuiltinClassType.PicklingError, ErrorMessages.PIDS_MUST_BE_ASCII_STRS); } - write(pickler, PickleUtils.OPCODE_PERSID); - writeASCII(pickler, pidStr); - writeASCII(pickler, T_NEWLINE); + pickler.write(this, PickleUtils.OPCODE_PERSID); + pickler.writeASCII(this, pidStr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } return true; } @@ -879,79 +1302,52 @@ private boolean savePers(VirtualFrame frame, PPickler pickler, Object obj) { } // memo methods - private void memoGet(PPickler pickler, int value) { - int len; - byte[] pdata; - if (pickler.isBin()) { - pdata = new byte[5]; + private void memoGet(PPickler pickler, int proto, int value) { + if (isBin(proto)) { if (value < 256) { - pdata[0] = PickleUtils.OPCODE_BINGET; - pdata[1] = (byte) (value & 0xff); - len = 2; + pickler.writeByteOp(this, PickleUtils.OPCODE_BINGET, value); } else if (Long.compareUnsigned(value, 0xffffffffL) <= 0) { - pdata[0] = PickleUtils.OPCODE_LONG_BINGET; - pdata[1] = (byte) (value & 0xff); - pdata[2] = (byte) ((value >> 8) & 0xff); - pdata[3] = (byte) ((value >> 16) & 0xff); - pdata[4] = (byte) ((value >> 24) & 0xff); - len = 5; + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG_BINGET, value); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINGET"); } } else { - pdata = new byte[30]; - pdata[0] = PickleUtils.OPCODE_GET; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + pickler.writeLongAsString(this, PickleUtils.OPCODE_GET, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } - write(pickler, pdata, len); } - private void memoPut(PPickler pickler, Object obj) { - if (pickler.isFast()) { + private void memoPut(PPickler pickler, int proto, boolean fastMode, Object obj) { + if (fastMode) { return; } int idx = pickler.memo.size(); pickler.memo.set(obj, idx); - if (pickler.proto >= 4) { - write(pickler, PickleUtils.OPCODE_MEMOIZE); - return; + if (proto >= 4) { + pickler.write(this, PickleUtils.OPCODE_MEMOIZE); } else { - byte[] pdata; - int len; - if (!pickler.isBin()) { - pdata = new byte[30]; - pdata[0] = PickleUtils.OPCODE_PUT; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); + if (!isBin(proto)) { + pickler.writeLongAsString(this, PickleUtils.OPCODE_PUT, idx, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } else { - pdata = new byte[5]; if (idx < 256) { - pdata[0] = PickleUtils.OPCODE_BINPUT; - pdata[1] = (byte) idx; - len = 2; + pickler.writeByteOp(this, PickleUtils.OPCODE_BINPUT, idx); } else if (Long.compareUnsigned(idx, 0xffffffffL) <= 0) { - pdata[0] = PickleUtils.OPCODE_LONG_BINPUT; - pdata[1] = (byte) (idx & 0xff); - pdata[2] = (byte) ((idx >> 8) & 0xff); - pdata[3] = (byte) ((idx >> 16) & 0xff); - pdata[4] = (byte) ((idx >> 24) & 0xff); - len = 5; + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG_BINPUT, idx); } else { // unlikely throw raise(PicklingError, ErrorMessages.MEMO_ID_TOO_LARGE_FOR_S, "LONG_BINPUT"); } } - write(pickler, pdata, len); } } // save methods - private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj, Object reduceValue) { + private void handleReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object reduceValue) { if (PGuards.isString(reduceValue)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, reduceValue); return; } @@ -959,10 +1355,10 @@ private void handleReduce(VirtualFrame frame, BoundaryCallData boundaryCallData, throw raise(PicklingError, ErrorMessages.S_MUST_RETURN_S_OR_S, T___REDUCE__, "string", "tuple"); } - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } - private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object arguments, Object obj) { + private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object arguments, Object obj) { // We're saving obj, and args is the 2-thru-5 tuple returned by the appropriate // __reduce__ method for obj. @@ -971,17 +1367,18 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, if (!isTuple(arguments)) { throw raise(PythonBuiltinClassType.SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC); } - int size = length(frame, arguments); + SequenceStorage argumentsStorage = getTupleStorage(arguments); + int size = argumentsStorage.length(); if (size < 2 || size > 6) { throw raise(PicklingError, ErrorMessages.TUPLE_RET_BY_REDUCE_2_6); } - Object callable = getItem(frame, arguments, 0); - Object argtup = getItem(frame, arguments, 1); - Object state = getItem(frame, arguments, size, 2, null); - Object listitems = getItem(frame, arguments, size, 3, PNone.NONE); - Object dictitems = getItem(frame, arguments, size, 4, PNone.NONE); - Object stateSetter = getItem(frame, arguments, size, 5, PNone.NONE); + Object callable = getItem(argumentsStorage, 0); + Object argtup = getItem(argumentsStorage, 1); + Object state = size > 2 ? getItem(argumentsStorage, 2) : null; + Object listitems = size > 3 ? getItem(argumentsStorage, 3) : PNone.NONE; + Object dictitems = size > 4 ? getItem(argumentsStorage, 4) : PNone.NONE; + Object stateSetter = size > 5 ? getItem(argumentsStorage, 5) : PNone.NONE; if (!isCallable(callable)) { throw raise(PicklingError, ErrorMessages.S_ITEM_REDUCE_MUST_BE_S, "first", "callable"); @@ -1013,7 +1410,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.S_ELEM_REDUCE_MUST_BE_S_NOT_P, "sixth", "a function", stateSetter); } - if (pickler.proto >= 2) { + if (proto >= 2) { Object name = lookupAttribute(frame, callable, T___NAME__); if (name != PNone.NO_VALUE) { final TruffleString stringName = asString(name); @@ -1026,9 +1423,11 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, } } - final int argtupSize = length(frame, argtup); + final SequenceStorage argtupStorage = getTupleStorage(argtup); + final int argtupSize = argtupStorage.length(); if (useNewobjEx) { + profileSeen(SEEN_NEWOBJ_EX); Object cls; Object args; Object kwargs; @@ -1037,29 +1436,30 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.LEN_OF_S_MUST_BE_D_NOT_D, "NEWOBJ_EX", 3, argtupSize); } - cls = getItem(frame, argtup, 0); + cls = getItem(argtupStorage, 0); if (!isType(cls)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "first", "NEWOBJ_EX", "a class", cls); } - args = getItem(frame, argtup, 1); + args = getItem(argtupStorage, 1); if (!isTuple(args)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "second", "NEWOBJ_EX", "a tuple", args); } - kwargs = getItem(frame, argtup, 2); + kwargs = getItem(argtupStorage, 2); if (!(kwargs instanceof PDict)) { throw raise(PicklingError, ErrorMessages.S_ITEM_FROM_S_MUST_BE_S_NOT_P, "third", "NEWOBJ_EX", "a dict", kwargs); } - if (pickler.proto >= 4) { - save(frame, pickler, cls, 0); - save(frame, pickler, args, 0); - save(frame, pickler, kwargs, 0); - write(pickler, PickleUtils.OPCODE_NEWOBJ_EX); + if (proto >= 4) { + saveReduceClass(frame, pickler, cls); + saveReduceArgs(frame, pickler, args); + saveReduceKwargs(frame, pickler, kwargs); + pickler.write(this, PickleUtils.OPCODE_NEWOBJ_EX); } else { PickleState st = getGlobalState(ctx.getCore()); - final int argsSize = length(frame, args); + final SequenceStorage argsStorage = getTupleStorage(args); + final int argsSize = argsStorage.length(); Object[] newargs = new Object[argsSize + 2]; Object clsNew; int i; @@ -1068,16 +1468,17 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, newargs[0] = clsNew; newargs[1] = cls; for (i = 0; i < argsSize; i++) { - Object item = getItem(frame, args, i); + Object item = getItem(argsStorage, i); newargs[i + 2] = item; } callable = callStarArgsAndKwArgs(frame, st.partial, newargs, kwargs); - save(frame, pickler, callable, 0); - save(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this)), 0); - write(pickler, PickleUtils.OPCODE_REDUCE); + saveReduceCallable(frame, pickler, callable); + saveReduceArgs(frame, pickler, PFactory.createEmptyTuple(PythonLanguage.get(this))); + pickler.write(this, PickleUtils.OPCODE_REDUCE); } } else if (useNewobj) { + profileSeen(SEEN_NEWOBJ); Object cls; Object newargtup; Object objClass; @@ -1088,7 +1489,7 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, throw raise(PicklingError, ErrorMessages.IS_EMPTY, "__newobj__ arglist"); } - cls = getItem(frame, argtup, 0); + cls = getItem(argtupStorage, 0); if (!isType(cls)) { throw raise(PicklingError, ErrorMessages.ARGS_0_FROM_S_ARGS_S, "__newobj__", "is not a type"); } @@ -1129,15 +1530,20 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // function. // Save the class and its __new__ arguments - save(frame, pickler, cls, 0); - newargtup = getItem(frame, argtup, PFactory.createIntSlice(PythonLanguage.get(this), 1, argtupSize, 1)); - save(frame, pickler, newargtup, 0); - write(pickler, PickleUtils.OPCODE_NEWOBJ); + saveReduceClass(frame, pickler, cls); + Object[] newargs = new Object[argtupSize - 1]; + for (int i = 1; i < argtupSize; i++) { + newargs[i - 1] = getItem(argtupStorage, i); + } + newargtup = createTuple(newargs); + saveReduceArgs(frame, pickler, newargtup); + pickler.write(this, PickleUtils.OPCODE_NEWOBJ); } else { + profileSeen(SEEN_PLAIN_REDUCE); // Not using NEWOBJ - save(frame, pickler, callable, 0); - save(frame, pickler, argtup, 0); - write(pickler, PickleUtils.OPCODE_REDUCE); + saveReduceCallable(frame, pickler, callable); + saveReduceArgs(frame, pickler, argtup); + pickler.write(this, PickleUtils.OPCODE_REDUCE); } // obj can be NULL when save_reduce() is used directly. A NULL obj means the caller do @@ -1149,25 +1555,28 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // memo int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(pickler, PickleUtils.OPCODE_POP); - memoGet(pickler, memoIndex); + pickler.write(this, PickleUtils.OPCODE_POP); + memoGet(pickler, proto, memoIndex); } else { - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } } if (listitems != null) { - batchList(frame, pickler, listitems); + profileSeen(SEEN_REDUCE_LISTITEMS); + batchList(frame, pickler, proto, listitems); } if (dictitems != null) { - batchDict(frame, pickler, dictitems); + profileSeen(SEEN_REDUCE_DICTITEMS); + batchDict(frame, pickler, proto, dictitems); } if (state != null) { + profileSeen(SEEN_REDUCE_STATE); if (stateSetter == null) { - save(frame, pickler, state, 0); - write(pickler, PickleUtils.OPCODE_BUILD); + saveReduceState(frame, pickler, state); + pickler.write(this, PickleUtils.OPCODE_BUILD); } else { // If a state_setter is specified, call it instead of load_build to update obj's // with its previous state. The first 4 save/write instructions push @@ -1176,151 +1585,124 @@ private void saveReduce(VirtualFrame frame, PythonContext ctx, PPickler pickler, // Finally, because state-updating routines only do in-place modification, the // whole operation has to be stack-transparent. Thus, we finally pop the call's // output from the stack. - save(frame, pickler, stateSetter, 0); - save(frame, pickler, obj, 0); - save(frame, pickler, state, 0); - write(pickler, PickleUtils.OPCODE_TUPLE2); - write(pickler, PickleUtils.OPCODE_REDUCE); - write(pickler, PickleUtils.OPCODE_POP); + saveReduceStateSetter(frame, pickler, stateSetter); + saveReduceObject(frame, pickler, obj); + saveReduceState(frame, pickler, state); + pickler.write(this, PickleUtils.OPCODE_TUPLE2); + pickler.write(this, PickleUtils.OPCODE_REDUCE); + pickler.write(this, PickleUtils.OPCODE_POP); } } } - private void saveNone(PPickler pickler, @SuppressWarnings("unused") Object obj) { - write(pickler, PickleUtils.OPCODE_NONE); + private void saveNone(PPickler pickler) { + pickler.write(this, PickleUtils.OPCODE_NONE); } - private void saveBool(VirtualFrame frame, PPickler pickler, Object obj) { - if (pickler.proto >= 2) { - write(pickler, isTrue(frame, obj) ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); + private void saveBool(PPickler pickler, int proto, boolean value) { + if (proto >= 2) { + pickler.write(this, value ? PickleUtils.OPCODE_NEWTRUE : PickleUtils.OPCODE_NEWFALSE); } else { // These aren't opcodes -- they're ways to pickle bools before protocol 2 so that // unpicklers written before bools were introduced unpickle them as ints, but // unpicklers after can recognize that bools were intended. Note that protocol 2 // added direct ways to pickle bools. - writeASCII(pickler, isTrue(frame, obj) ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE); + pickler.writeASCII(this, value ? PickleUtils.T_PROTO_LE2_TRUE : PickleUtils.T_PROTO_LE2_FALSE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } - private void saveLong(VirtualFrame frame, PPickler pickler, Object obj) { - TruffleString repr; - try { - long value = asLong(frame, obj); - if (value <= 0x7fffffffL && value >= (-0x7fffffffL - 1)) { - // result fits in a signed 4-byte integer. Note: we can't use -0x80000000L in - // the above condition because some compilers (e.g., MSVC) will promote - // 0x80000000L to an unsigned type before applying the unary minus when - // sizeof(long) <= 4. The resulting value stays unsigned which is commonly not - // what we want, so MSVC happily warns us about it. However, that result would - // have been fine because we guard for sizeof(long) <= 4 which turns the - // condition true in that particular case. - byte[] pdata; - int len; - - if (pickler.isBin()) { - pdata = new byte[5]; - pdata[1] = (byte) (value & 0xff); - pdata[2] = (byte) ((value >> 8) & 0xff); - pdata[3] = (byte) ((value >> 16) & 0xff); - pdata[4] = (byte) ((value >> 24) & 0xff); - - if ((pdata[4] != 0) || (pdata[3] != 0)) { - pdata[0] = PickleUtils.OPCODE_BININT; - len = 5; - } else if (pdata[2] != 0) { - pdata[0] = PickleUtils.OPCODE_BININT2; - len = 3; - } else { - pdata[0] = PickleUtils.OPCODE_BININT1; - len = 2; - } - } else { - pdata = new byte[32]; - pdata[0] = PickleUtils.OPCODE_INT; - len = PickleUtils.toAsciiBytesWithNewLine(pdata, 1, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); - } - write(pickler, pdata, len); - return; + private void saveLong(PPickler pickler, int proto, int value) { + if (isBin(proto)) { + if (value >= 0 && value < (1 << 8)) { + pickler.writeByteOp(this, PickleUtils.OPCODE_BININT1, value); + } else if (value >= 0 && value < (1 << 16)) { + pickler.writeShortOp(this, PickleUtils.OPCODE_BININT2, value); + } else { + pickler.writeIntOp(this, PickleUtils.OPCODE_BININT, value); } - } catch (PException e) { - e.expectCached(OverflowError, ensureErrProfile()); + } else { + pickler.writeLongAsString(this, PickleUtils.OPCODE_INT, value, ensureTsFromLongNode(), ensureTsCopyToByteArrayNode()); } + } - if (pickler.proto >= 2) { - byte[] header = new byte[5]; - // Linear-time pickling. - final int sign = getSign(obj); - if (sign == 0) { - header[0] = PickleUtils.OPCODE_LONG1; - header[1] = 0; - write(pickler, header, 2); - } + private void saveLong(PPickler pickler, int proto, long value) { + int intValue = (int) value; + if (intValue == value) { + saveLong(pickler, proto, intValue); + } else { + saveLongLarge(pickler, proto, value); + } + } + + private void saveLong(VirtualFrame frame, PPickler pickler, int proto, PInt value) { + try { + saveLong(pickler, proto, value.longValueExact()); + } catch (OverflowException e) { + saveLongLarge(frame, pickler, proto, value); + } + } - final int nbits = getNumBits(obj); - // How many bytes do we need? There are nbits >> 3 full bytes of data, and nbits & 7 - // leftover bits. If there are any leftover bits, then we clearly need another byte. - // What's not so obvious is that we *probably* need another byte even if there - // aren't any leftovers: the most-significant bit of the most-significant byte acts - // like a sign bit, and it's usually got a sense opposite of the one we need. The - // exception is ints of the form -(2**(8*j-1)) for j > 0. Such an int is its own - // 256's-complement, so has the right sign bit even without the extra byte. That's a - // pain to check for in advance, though, so we always grab an extra byte at the - // start, and cut it back later if possible. + private void saveLongLarge(PPickler pickler, int proto, long value) { + if (proto >= 2) { + // Count the significant bits excluding the sign extension, then add a sign bit. + int nbits = Long.SIZE - Long.numberOfLeadingZeros(value < 0 ? ~value : value); int nbytes = (nbits >> 3) + 1; - if (Long.compareUnsigned(nbytes, 0x7fffffffL) > 0) { - throw raise(OverflowError, ErrorMessages.S_TO_LARGE_TO_PICKLE, "int"); - } - byte[] pdata = longAsBytes(obj, nbytes, false); - // If the int is negative, this may be a byte more than needed. This is so iff the - // MSB is all redundant sign bits. - if (sign < 0 && nbytes > 1 && pdata[nbytes - 1] == (byte) 0xff && (pdata[nbytes - 2] & 0x80) != 0) { - nbytes--; + pickler.writeByteOp(this, PickleUtils.OPCODE_LONG1, nbytes); + pickler.ensureBufferSpace(this, nbytes); + for (int i = 0; i < nbytes; i++) { + pickler.outputBuffer[pickler.outputLen++] = (byte) value; + value >>= Byte.SIZE; } - int size; + } else { + TruffleString repr = ensureTsFromLongNode().execute(value, TS_ENCODING, true); + pickler.write(this, PickleUtils.OPCODE_LONG); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + } + } + + private void saveLongLarge(VirtualFrame frame, PPickler pickler, int proto, PInt value) { + if (proto >= 2) { + // BigInteger already provides the minimal signed two's-complement representation. + byte[] data = value.toByteArray(); + int nbytes = data.length; if (nbytes < 256) { - header[0] = PickleUtils.OPCODE_LONG1; - header[1] = (byte) nbytes; - size = 2; + pickler.writeByteOp(this, PickleUtils.OPCODE_LONG1, nbytes); } else { - header[0] = PickleUtils.OPCODE_LONG4; - size = nbytes; - for (int i = 1; i < 5; i++) { - header[i] = (byte) (size & 0xff); - size >>= 8; - } - size = 5; + pickler.writeIntOp(this, PickleUtils.OPCODE_LONG4, nbytes); + } + pickler.ensureBufferSpace(this, nbytes); + // BigInteger's bytes are big endian; pickle requires little endian. + for (int i = nbytes - 1; i >= 0; i--) { + pickler.outputBuffer[pickler.outputLen++] = data[i]; } - - write(pickler, header, size); - write(pickler, pdata, nbytes); - } else { - repr = repr(frame, obj); - write(pickler, PickleUtils.OPCODE_LONG); - writeASCII(pickler, asStringStrict(repr)); - writeASCII(pickler, T_L_NEW_LINE); + TruffleString repr = repr(frame, value); + pickler.write(this, PickleUtils.OPCODE_LONG); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_L_NEW_LINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } - private void saveFloat(VirtualFrame frame, PPickler pickler, Object obj, Node inliningTarget, PyFloatAsDoubleNode asDoubleNode) { - final double value = asDoubleNode.execute(frame, inliningTarget, obj); - if (pickler.isBin()) { - byte[] pdata = new byte[9]; - pdata[0] = PickleUtils.OPCODE_BINFLOAT; - NumericSupport.bigEndian().putDouble(pdata, 1, value); - write(pickler, pdata, 9); + private void saveFloat(PPickler pickler, int proto, double value) { + if (isBin(proto)) { + pickler.write(this, PickleUtils.OPCODE_BINFLOAT); + pickler.ensureBufferSpace(this, 8); + NumericSupport.bigEndian().putDouble(pickler.outputBuffer, pickler.outputLen, value); + pickler.outputLen += 8; } else { - write(pickler, PickleUtils.OPCODE_FLOAT); + pickler.write(this, PickleUtils.OPCODE_FLOAT); TruffleString repr = PickleUtils.doubleToAsciiString(value); - writeASCII(pickler, repr); - writeASCII(pickler, T_NEWLINE); + pickler.writeASCII(this, repr, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } } - private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { - Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PBytes obj) { + Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); + PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { - if (pickler.proto < 3) { + if (proto < 3) { // Older pickle protocols do not have an opcode for pickling bytes objects. // Therefore, we need to fake the copy protocol (i.e., the __reduce__ method) to // permit bytes object unpickling. Here we use a hack to be compatible with @@ -1333,105 +1715,95 @@ private void saveBytes(VirtualFrame frame, PythonContext ctx, PPickler pickler, // need to do this with newer protocols. Object reduceValue; - if (getBufferLibrary().getBufferLength(buffer) == 0) { + if (bufferLib.getBufferLength(buffer) == 0) { reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PBytes), createTuple()); } else { PickleState st = getGlobalState(ctx.getCore()); - final TruffleString unicodeStr = PickleUtils.decodeLatin1Strict(getBufferLibrary().getCopiedByteArray(buffer), ensureTsFromByteArrayWithCompaction()); + final TruffleString unicodeStr = PickleUtils.decodeLatin1Strict(bufferLib.getCopiedByteArray(buffer), ensureTsFromByteArrayWithCompaction()); reduceValue = createTuple(st.codecsEncode, createTuple(unicodeStr, LATIN1)); } // save_reduce() will memoize the object automatically. - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } else { - byte[] bytes = getBufferLibrary().getCopiedByteArray(buffer); - saveBytesData(frame, pickler, obj, bytes, bytes.length); + saveBytesData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } finally { - getBufferLibrary().release(buffer, frame, interopCallData); + bufferLib.release(buffer); } } - private void saveBytesData(VirtualFrame frame, PPickler pickler, Object obj, byte[] data, int size) { - assert pickler.proto >= 3; - byte[] header = new byte[9]; - int len; + private void saveBytesData(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { + assert proto >= 3; + int size = bufferLib.getBufferLength(buffer); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); if (size <= 0xff) { - header[0] = PickleUtils.OPCODE_SHORT_BINBYTES; - header[1] = (byte) size; - len = 2; - } else if (Long.compareUnsigned(size, 0xffffffffL) < 0) { - header[0] = PickleUtils.OPCODE_BINBYTES; - header[1] = (byte) (size & 0xff); - header[2] = (byte) ((size >> 8) & 0xff); - header[3] = (byte) ((size >> 16) & 0xff); - header[4] = (byte) ((size >> 24) & 0xff); - len = 5; - } else if (pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_BINBYTES8; - PickleUtils.writeSize64(header, 1, size); - len = 9; + pickler.writeByteOp(this, PickleUtils.OPCODE_SHORT_BINBYTES, size); } else { - throw raise(OverflowError, ErrorMessages.SER_OVER_4GB); - } - - writeBytes(frame, pickler, header, len, data, size, obj); - memoPut(pickler, obj); - } - - private void writeUnicodeBinary(VirtualFrame frame, PPickler pickler, Object obj) { - Object encoded = null; - byte[] header = new byte[9]; - int len; - byte[] data = PickleUtils.encodeUTF8Strict(asStringStrict(obj), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - - if (data == null) { - // Issue #8383: for strings with lone surrogates, fallback on the "surrogatepass" - // error handler. - encoded = getItem(frame, encode(frame, obj, T_UTF8, T_ERRORS_SURROGATEPASS), 0); - // Checkstyle: stop - //@formatter:off - // data = PickleUtils.encodeUTF8Strict(asStringStrict(encoded), ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - // Checkstyle: start - //@formatter:on - // TODO: [GR-39571] TruffleStrings: allow preservation of UTF-16 surrogate - data = toBytes(frame, encoded); - } - - int size = data.length; - - if (size <= 0xff && pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_SHORT_BINUNICODE; - header[1] = (byte) (size & 0xff); - len = 2; - } else if (Long.compareUnsigned(size, 0xffffffffL) <= 0) { - header[0] = PickleUtils.OPCODE_BINUNICODE; - header[1] = (byte) (size & 0xff); - header[2] = (byte) ((size >> 8) & 0xff); - header[3] = (byte) ((size >> 16) & 0xff); - header[4] = (byte) ((size >> 24) & 0xff); - len = 5; - } else if (pickler.proto >= 4) { - header[0] = PickleUtils.OPCODE_BINUNICODE8; - PickleUtils.writeSize64(header, 1, size); - len = 9; + pickler.writeIntOp(this, PickleUtils.OPCODE_BINBYTES, size); + } + + if (bypassBuffer && pickler.write != null) { + flushToFile(frame, pickler); + ensureCallNode().execute(frame, pickler.write, obj); + pickler.clearBuffer(); + } else { + pickler.writeBuffer(this, buffer, size, bufferLib); + } + + if (bypassBuffer && wasFraming) { + pickler.framing = true; + } + memoPut(pickler, proto, fastMode, obj); + } + + private void writeUnicodeBinary(Node node, VirtualFrame frame, PPickler pickler, int proto, TruffleString string, + TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode, + FlushToFileNode flushToFileNode, CallNode callNode) { + TruffleString utf8 = switchEncodingNode.execute(string, TruffleString.Encoding.UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + int size = utf8.byteLength(TruffleString.Encoding.UTF_8); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); + + if (bypassBuffer && pickler.write != null) { + pickler.writeIntOp(node, PickleUtils.OPCODE_BINUNICODE, size); + byte[] data = new byte[size]; + copyToByteArrayNode.execute(utf8, 0, data, 0, size, TruffleString.Encoding.UTF_8); + flushToFileNode.execute(frame, pickler); + callNode.execute(frame, pickler.write, PFactory.createBytes(PythonLanguage.get(node), data, size)); + pickler.clearBuffer(); } else { - throw raise(OverflowError, ErrorMessages.SER_OVER_4GB); + if (size <= 0xff && proto >= 4) { + pickler.writeByteOp(node, PickleUtils.OPCODE_SHORT_BINUNICODE, size); + } else { + pickler.writeIntOp(node, PickleUtils.OPCODE_BINUNICODE, size); + } + pickler.writeUtf8Converted(node, utf8, copyToByteArrayNode); + } + + if (bypassBuffer && wasFraming) { + pickler.framing = true; } + } + + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, TruffleString obj) { + saveUnicode(frame, pickler, proto, fastMode, obj, obj); + } - writeBytes(frame, pickler, header, len, data, size, encoded); + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PString obj) { + saveUnicode(frame, pickler, proto, fastMode, obj, asStringStrict(obj)); } - private void saveUnicode(VirtualFrame frame, PPickler pickler, Object obj) { - if (pickler.isBin()) { - writeUnicodeBinary(frame, pickler, obj); + private void saveUnicode(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, TruffleString string) { + if (isBin(proto)) { + writeUnicodeBinary(this, frame, pickler, proto, string, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode(), ensureFlushToFileNode(), ensureCallNode()); } else { - byte[] encoded = PickleUtils.rawUnicodeEscape(asStringStrict(obj), ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); - write(pickler, PickleUtils.OPCODE_UNICODE); - write(pickler, encoded); - writeASCII(pickler, T_NEWLINE); + pickler.write(this, PickleUtils.OPCODE_UNICODE); + pickler.writeRawUnicodeEscape(this, string, ensureTsCodePointLengthNode(), ensureTsCodePointAtIndexUTF32Node()); + pickler.writeASCII(this, T_NEWLINE, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { @@ -1445,18 +1817,18 @@ private void batchDictExact(VirtualFrame frame, PPickler pickler, PDict dict) { } HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); - save(frame, pickler, getKeyNode.executeCached(storage, it), 0); - save(frame, pickler, getValueNode.executeCached(storage, it), 0); - write(pickler, PickleUtils.OPCODE_SETITEM); + saveDictKey(frame, pickler, getKeyNode.executeCached(storage, it)); + saveDictValue(frame, pickler, getValueNode.executeCached(storage, it)); + pickler.write(this, PickleUtils.OPCODE_SETITEM); } else { // Write in batches of BATCHSIZE. saveDictHashingStorageBatched(frame, pickler, storage); } } - private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { + private void batchDict(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { assert iterator != null; - if (pickler.proto == 0) { + if (proto == 0) { // SETITEMS isn't available; do one at a time. saveDictIterator(frame, pickler, iterator); } else { @@ -1465,138 +1837,108 @@ private void batchDict(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, Object obj) { - byte[] header = new byte[3]; - int len; - - if (pickler.isFast()) { + private void saveDict(VirtualFrame frame, Node inliningTarget, PyObjectCallMethodObjArgs callMethod, PPickler pickler, int proto, boolean fastMode, PDict obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } // Create an empty dict. - if (pickler.isBin()) { - header[0] = PickleUtils.OPCODE_EMPTY_DICT; - len = 1; + if (isBin(proto)) { + pickler.write(this, PickleUtils.OPCODE_EMPTY_DICT); } else { - header[0] = PickleUtils.OPCODE_MARK; - header[1] = PickleUtils.OPCODE_DICT; - len = 2; + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_DICT); } - write(pickler, header, len); - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); - if (length(frame, obj) > 0) { - if (PGuards.isDict(obj) && pickler.proto > 0) { - batchDictExact(frame, pickler, (PDict) obj); + if (getHashingStorageLength(obj.getDictStorage()) > 0) { + if (proto > 0) { + batchDictExact(frame, pickler, obj); } else { final Object items = callMethod.execute(frame, inliningTarget, obj, T_ITEMS); - batchDict(frame, pickler, getIter(frame, items)); + batchDict(frame, pickler, proto, getIter(frame, items)); } } - if (pickler.isFast()) { + if (fastMode) { fastSaveLeave(pickler, obj); } } - private void batchSetExact(VirtualFrame frame, PPickler pickler, PSet set) { - saveSetHashingStorageBatched(frame, pickler, set.getDictStorage()); - } - - private void batchSet(VirtualFrame frame, PPickler pickler, Object obj) { - Object iterator = getIter(frame, obj); - int setSize = length(frame, obj); - int i; - do { - i = 0; - write(pickler, PickleUtils.OPCODE_MARK); - while (true) { - Object item; - try { - item = getNextItem(frame, iterator); - } catch (IteratorExhausted e) { - break; - } - save(frame, pickler, item, 0); - if (++i == PickleUtils.BATCHSIZE) { - break; - } - } - write(pickler, PickleUtils.OPCODE_ADDITEMS); - if (length(frame, obj) != setSize) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.CHANGED_SIZE_DURING_ITERATION, "set"); - } - } while (i == PickleUtils.BATCHSIZE); - } - - private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj) { + private void saveSet(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PSet obj) { Object reduceValue; - if (pickler.proto < 4) { + if (proto < 4) { Object items = createList(frame, obj); reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PSet), createTuple(items)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); return; } - write(pickler, PickleUtils.OPCODE_EMPTY_SET); - memoPut(pickler, obj); + pickler.write(this, PickleUtils.OPCODE_EMPTY_SET); + memoPut(pickler, proto, fastMode, obj); - final int setSize = length(frame, obj); - if (setSize == 0) { + HashingStorage storage = obj.getDictStorage(); + if (getHashingStorageLength(storage) == 0) { // nothing to do return; } // Write in batches of BATCHSIZE. - if (obj instanceof PSet set) { - batchSetExact(frame, pickler, set); - } else { - batchSet(frame, pickler, obj); - } + saveSetHashingStorageBatched(frame, pickler, storage); } - private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj) { - if (pickler.isFast()) { + private void saveFrozenset(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PFrozenSet obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } - if (pickler.proto < 4) { + if (proto < 4) { Object items = createList(frame, obj); Object reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PFrozenSet), createTuple(items)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); return; } - write(pickler, PickleUtils.OPCODE_MARK); + pickler.write(this, PickleUtils.OPCODE_MARK); - if (obj instanceof PFrozenSet set) { - saveSetHashingStorage(frame, pickler, set.getDictStorage()); - } else { - final Object iterator = getIter(frame, obj); - saveFrozenSetIterator(frame, pickler, iterator); - } + saveSetHashingStorage(frame, pickler, obj.getDictStorage()); // If the object is already in the memo, this means it is recursive. In this case, throw // away everything we put on the stack, and fetch the object back from the memo. int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - write(pickler, PickleUtils.OPCODE_POP_MARK); - memoGet(pickler, memoIndex); + pickler.write(this, PickleUtils.OPCODE_POP_MARK); + memoGet(pickler, proto, memoIndex); return; } - write(pickler, PickleUtils.OPCODE_FROZENSET); - memoPut(pickler, obj); + pickler.write(this, PickleUtils.OPCODE_FROZENSET); + memoPut(pickler, proto, fastMode, obj); } - private void batchListExact(VirtualFrame frame, PPickler pickler, Object obj) { - final SequenceStorage storage = getSequenceStorage(obj); + private void batchListExact(VirtualFrame frame, PPickler pickler, PList obj) { + SequenceStorage storage = obj.getSequenceStorage(); + if (pickler.persFunc == null) { + if (storage instanceof IntSequenceStorage intStorage) { + profileSeen(SEEN_INT_STORAGE); + batchIntList(frame, pickler, intStorage); + return; + } else if (storage instanceof LongSequenceStorage longStorage) { + profileSeen(SEEN_LONG_STORAGE); + batchLongList(frame, pickler, longStorage); + return; + } else if (storage instanceof DoubleSequenceStorage doubleStorage) { + profileSeen(SEEN_DOUBLE_STORAGE); + batchDoubleList(frame, pickler, doubleStorage); + return; + } + } + profileSeen(SEEN_GENERIC_STORAGE); Object item; - if (length(frame, obj) == 1) { - item = getItem(frame, storage, 0); - save(frame, pickler, item, 0); - write(pickler, PickleUtils.OPCODE_APPEND); + if (storage.length() == 1) { + item = getItem(storage, 0); + saveListElement(frame, pickler, item); + pickler.write(this, PickleUtils.OPCODE_APPEND); return; } @@ -1605,22 +1947,118 @@ private void batchListExact(VirtualFrame frame, PPickler pickler, Object obj) { int thisBatch; do { thisBatch = 0; - write(pickler, PickleUtils.OPCODE_MARK); - while (total < length(frame, obj)) { - item = getItem(frame, storage, total); - save(frame, pickler, item, 0); + pickler.write(this, PickleUtils.OPCODE_MARK); + while (total < storage.length()) { + item = getItem(storage, total); + saveListElement(frame, pickler, item); total++; if (++thisBatch == PickleUtils.BATCHSIZE) { break; } } - write(pickler, PickleUtils.OPCODE_APPENDS); - } while (total < length(frame, obj)); + pickler.write(this, PickleUtils.OPCODE_APPENDS); + // It could have been mutated as a side effect of the reduce calls or the file write + storage = obj.getSequenceStorage(); + } while (total < storage.length()); + LoopNode.reportLoopCount(this, total); + } + + private void batchIntList(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { + opcodeBoundary(frame, pickler); + int proto = pickler.getProto(); + int length = storage.length(); + + if (length == 1) { + saveLong(pickler, proto, storage.getIntItemNormalized(0)); + pickler.write(this, PickleUtils.OPCODE_APPEND); + return; + } + + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + pickler.write(this, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } + saveLong(pickler, proto, storage.getIntItemNormalized(i)); + } + pickler.write(this, PickleUtils.OPCODE_APPENDS); + } + LoopNode.reportLoopCount(this, length); + } + + private void batchLongList(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { + opcodeBoundary(frame, pickler); + int proto = pickler.getProto(); + int length = storage.length(); + + if (length == 1) { + saveLong(pickler, proto, storage.getLongItemNormalized(0)); + pickler.write(this, PickleUtils.OPCODE_APPEND); + return; + } + + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + pickler.write(this, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } + saveLong(pickler, proto, storage.getLongItemNormalized(i)); + } + pickler.write(this, PickleUtils.OPCODE_APPENDS); + } + LoopNode.reportLoopCount(this, length); } - private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { + private void batchDoubleList(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { + opcodeBoundary(frame, pickler); + int proto = pickler.getProto(); + int length = storage.length(); + + if (length == 1) { + saveFloat(pickler, proto, storage.getDoubleItemNormalized(0)); + pickler.write(this, PickleUtils.OPCODE_APPEND); + return; + } + + for (int batchStart = 0; batchStart < length; batchStart += PickleUtils.BATCHSIZE) { + int batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + pickler.write(this, PickleUtils.OPCODE_MARK); + for (int i = batchStart; i < batchEnd; i++) { + boolean didFlush = opcodeBoundary(frame, pickler); + // To make sure we don't go out-of-bounds if the file write mutated the list + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, didFlush && length != storage.length())) { + length = storage.length(); + batchEnd = batchStart + Math.min(PickleUtils.BATCHSIZE, length - batchStart); + if (i >= batchEnd) { + break; + } + } + saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); + } + pickler.write(this, PickleUtils.OPCODE_APPENDS); + } + LoopNode.reportLoopCount(this, length); + } + + private void batchList(VirtualFrame frame, PPickler pickler, int proto, Object iterator) { assert iterator != null; - if (pickler.proto == 0) { + if (proto == 0) { // APPENDS isn't available; do one at a time. saveListIterator(frame, pickler, iterator); } else { @@ -1629,175 +2067,222 @@ private void batchList(VirtualFrame frame, PPickler pickler, Object iterator) { } } - private void saveList(VirtualFrame frame, PPickler pickler, Object obj) { - byte[] header = new byte[3]; - int len; - - if (pickler.isFast()) { + private void saveList(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PList obj) { + if (fastMode) { fastSaveEnter(pickler, obj); } // Create an empty list. - if (pickler.isBin()) { - header[0] = PickleUtils.OPCODE_EMPTY_LIST; - len = 1; + if (isBin(proto)) { + pickler.write(this, PickleUtils.OPCODE_EMPTY_LIST); } else { - header[0] = PickleUtils.OPCODE_MARK; - header[1] = PickleUtils.OPCODE_LIST; - len = 2; + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_LIST); } - write(pickler, header, len); - len = length(frame, obj); - memoPut(pickler, obj); + int len = obj.getSequenceStorage().length(); + memoPut(pickler, proto, fastMode, obj); if (len != 0) { - // Materialize the list elements. - if (PGuards.isList(obj) && pickler.proto > 0) { + if (proto > 0) { batchListExact(frame, pickler, obj); } else { - batchList(frame, pickler, getIter(frame, obj)); + batchList(frame, pickler, proto, getIter(frame, obj)); } } - if (pickler.isFast()) { + if (fastMode) { fastSaveLeave(pickler, obj); } } - private void storeTupleElements(VirtualFrame frame, PPickler pickler, Object obj, int len) { + private void storeTupleElements(VirtualFrame frame, PPickler pickler, SequenceStorage storage, int len) { // A helper for save_tuple. Push the len elements in tuple t on the stack - assert PyObjectSizeNode.executeUncached(obj) == len; + assert storage.length() == len; + if (pickler.persFunc == null) { + if (storage instanceof IntSequenceStorage intStorage) { + profileSeen(SEEN_INT_STORAGE); + storeIntTupleElements(frame, pickler, intStorage); + return; + } else if (storage instanceof LongSequenceStorage longStorage) { + profileSeen(SEEN_LONG_STORAGE); + storeLongTupleElements(frame, pickler, longStorage); + return; + } else if (storage instanceof DoubleSequenceStorage doubleStorage) { + profileSeen(SEEN_DOUBLE_STORAGE); + storeDoubleTupleElements(frame, pickler, doubleStorage); + return; + } + } + profileSeen(SEEN_GENERIC_STORAGE); for (int i = 0; i < len; i++) { - Object element = getItem(frame, obj, i); - save(frame, pickler, element, 0); + saveTupleElement(frame, pickler, getItem(storage, i)); } + LoopNode.reportLoopCount(this, len); } - private void saveTuple(VirtualFrame frame, PPickler pickler, Object obj) { - int len = length(frame, obj); + private void storeIntTupleElements(VirtualFrame frame, PPickler pickler, IntSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveLong(pickler, proto, storage.getIntItemNormalized(i)); + } + LoopNode.reportLoopCount(this, storage.length()); + } - if (len == 0) { - byte[] pdata = new byte[2]; + private void storeLongTupleElements(VirtualFrame frame, PPickler pickler, LongSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveLong(pickler, proto, storage.getLongItemNormalized(i)); + } + LoopNode.reportLoopCount(this, storage.length()); + } + + private void storeDoubleTupleElements(VirtualFrame frame, PPickler pickler, DoubleSequenceStorage storage) { + int proto = pickler.getProto(); + for (int i = 0; i < storage.length(); i++) { + opcodeBoundary(frame, pickler); + saveFloat(pickler, proto, storage.getDoubleItemNormalized(i)); + } + LoopNode.reportLoopCount(this, storage.length()); + } - if (pickler.proto != 0) { - pdata[0] = PickleUtils.OPCODE_EMPTY_TUPLE; - len = 1; + private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PTuple obj) { + SequenceStorage storage = obj.getSequenceStorage(); + saveTuple(frame, pickler, proto, fastMode, obj, storage, storage.length()); + } + + private void saveNativeTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj) { + SequenceStorage storage = getTupleStorage(obj); + saveTuple(frame, pickler, proto, fastMode, obj, storage, storage.length()); + } + + private void saveTuple(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, SequenceStorage storage, int len) { + + if (len == 0) { + if (proto != 0) { + pickler.write(this, PickleUtils.OPCODE_EMPTY_TUPLE); } else { - pdata[0] = PickleUtils.OPCODE_MARK; - pdata[1] = PickleUtils.OPCODE_TUPLE; - len = 2; + pickler.write(this, PickleUtils.OPCODE_MARK, PickleUtils.OPCODE_TUPLE); } - - write(pickler, pdata, len); return; } // The tuple isn't in the memo now. If it shows up there after saving the tuple // elements, the tuple must be recursive, in which case we'll pop everything we put on // the stack, and fetch its value from the memo. - if (len <= 3 && pickler.proto >= 2) { + if (len <= 3 && proto >= 2) { // Use TUPLE{1,2,3} opcodes. - storeTupleElements(frame, pickler, obj, len); + storeTupleElements(frame, pickler, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { // pop the len elements for (int i = 0; i < len; i++) { - write(pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_POP); } // fetch from memo - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. - write(pickler, TUPLE_LEN_2_OPCODE[len]); + pickler.write(this, TUPLE_LEN_2_OPCODE[len]); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); return; } // proto < 2 and len > 0, or proto >= 2 and len > 3. Generate MARK e1 e2 ... TUPLE - write(pickler, PickleUtils.OPCODE_MARK); - storeTupleElements(frame, pickler, obj, len); + pickler.write(this, PickleUtils.OPCODE_MARK); + storeTupleElements(frame, pickler, storage, len); int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { // pop the stack stuff we pushed - if (pickler.isBin()) { - write(pickler, PickleUtils.OPCODE_POP_MARK); + if (isBin(proto)) { + pickler.write(this, PickleUtils.OPCODE_POP_MARK); } else { // Note that we pop one more than len, to remove the MARK too. for (int i = 0; i <= len; i++) { - write(pickler, PickleUtils.OPCODE_POP); + pickler.write(this, PickleUtils.OPCODE_POP); } } // fetch from memo - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } else { // Not recursive. - write(pickler, PickleUtils.OPCODE_TUPLE); + pickler.write(this, PickleUtils.OPCODE_TUPLE); } - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } - private void saveBytearrayData(VirtualFrame frame, PPickler pickler, Object obj, byte[] data, int size) { - assert pickler.proto >= 5; - if (size < 0) { - return; - } + private void saveBytearrayData(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, Object obj, Object buffer, PythonBufferAccessLibrary bufferLib) { + assert proto >= 5; - byte[] header = new byte[9]; + int size = bufferLib.getBufferLength(buffer); + boolean wasFraming = pickler.framing; + boolean bypassBuffer = bypassBuffer(pickler, size); - header[0] = PickleUtils.OPCODE_BYTEARRAY8; - PickleUtils.writeSize64(header, 1, size); + // Our sizes are ints, but the protocol expects 8 bytes + pickler.ensureBufferSpace(this, 9); + pickler.outputBuffer[pickler.outputLen++] = PickleUtils.OPCODE_BYTEARRAY8; + PickleUtils.writeSize64(pickler.outputBuffer, pickler.outputLen, size); + pickler.outputLen += 8; - int len = 9; - writeBytes(frame, pickler, header, len, data, size, obj); - memoPut(pickler, obj); + if (bypassBuffer && pickler.write != null) { + flushToFile(frame, pickler); + ensureCallNode().execute(frame, pickler.write, obj); + pickler.clearBuffer(); + } else { + pickler.writeBuffer(this, buffer, size, bufferLib); + } + + if (bypassBuffer && wasFraming) { + pickler.framing = true; + } + memoPut(pickler, proto, fastMode, obj); } - private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, Object obj, InteropCallData interopCallData) { - Object buffer = getBufferAcquireLibrary().acquireReadonly(obj, frame, interopCallData); + private void saveBytearray(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PByteArray obj) { + Object buffer = getBufferAcquireLibrary().acquireReadonly(obj); + PythonBufferAccessLibrary bufferLib = getBufferLibrary(); try { - if (pickler.proto < 5) { + if (proto < 5) { // Older pickle protocols do not have an opcode for pickling bytearrays. Object reduceValue; final PythonBuiltinClass byteArrayClass = ctx.getCore().lookupType(PythonBuiltinClassType.PByteArray); - if (getBufferLibrary().getBufferLength(buffer) == 0) { + if (bufferLib.getBufferLength(buffer) == 0) { reduceValue = createTuple(byteArrayClass, createTuple()); } else { - byte[] bytes = getBufferLibrary().getCopiedByteArray(buffer); + byte[] bytes = bufferLib.getCopiedByteArray(buffer); reduceValue = createTuple(byteArrayClass, createTuple(PFactory.createBytes(ctx.getLanguage(inliningTarget), bytes))); } // save_reduce() will memoize the object automatically. - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } else { - saveBytearrayData(frame, pickler, obj, getBufferLibrary().getCopiedByteArray(buffer), length(frame, obj)); + saveBytearrayData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } finally { - getBufferLibrary().release(buffer, frame, interopCallData); + bufferLib.release(buffer); } } - private void savePicklebuffer(VirtualFrame frame, PPickler pickler, PPickleBuffer obj) { - if (pickler.proto < 5) { + private void savePickleBuffer(VirtualFrame frame, PPickler pickler, int proto, boolean fastMode, PPickleBuffer obj) { + if (proto < 5) { throw raise(PicklingError, ErrorMessages.PICKLEBUFF_CANNOT_PICKLE_WITH_PROTO5); } Object buffer = obj.getView(); PythonBufferAccessLibrary bufferLib = getBufferLibrary(); - int bytesLen = bufferLib.getBufferLength(buffer); - byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); boolean inBand = true; if (pickler.bufferCallback != null) { - Object ret = getCallNode().execute(frame, pickler.bufferCallback, obj); + Object ret = ensureCallNode().execute(frame, pickler.bufferCallback, obj); inBand = isTrue(frame, ret); } @@ -1805,38 +2290,42 @@ private void savePicklebuffer(VirtualFrame frame, PPickler pickler, PPickleBuffe if (inBand) { // Write data in-band if (readOnly) { - saveBytesData(frame, pickler, obj, bytes, bytesLen); + saveBytesData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } else { - saveBytearrayData(frame, pickler, obj, bytes, bytesLen); + saveBytearrayData(frame, pickler, proto, fastMode, obj, buffer, bufferLib); } } else { // Write data out-of-band - write(pickler, PickleUtils.OPCODE_NEXT_BUFFER); + pickler.write(this, PickleUtils.OPCODE_NEXT_BUFFER); if (readOnly) { - write(pickler, PickleUtils.OPCODE_READONLY_BUFFER); + pickler.write(this, PickleUtils.OPCODE_READONLY_BUFFER); } } } - private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler pickler, Object obj, Object singleton) { + private void saveSingletonType(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object singleton) { Object reduceValue = createTuple(ctx.getCore().lookupType(PythonBuiltinClassType.PythonClass), createTuple(singleton)); - saveReduce(frame, ctx, pickler, reduceValue, obj); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, obj); } - private void saveType(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj) { - if (isBuiltinClass(obj, PythonBuiltinClassType.PNone)) { - saveSingletonType(frame, ctx, pickler, obj, PNone.NONE); - } else if (isBuiltinClass(obj, PythonBuiltinClassType.PEllipsis)) { - saveSingletonType(frame, ctx, pickler, obj, PEllipsis.INSTANCE); - } else if (isBuiltinClass(obj, PythonBuiltinClassType.PNotImplemented)) { - saveSingletonType(frame, ctx, pickler, obj, PNotImplemented.NOT_IMPLEMENTED); + private void saveType(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, PythonManagedClass obj) { + if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNone) { + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNone.NONE); + } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PEllipsis) { + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PEllipsis.INSTANCE); + } else if (obj instanceof PythonBuiltinClass cls && cls.getType() == PythonBuiltinClassType.PNotImplemented) { + saveSingletonType(frame, ctx, pickler, proto, fastMode, obj, PNotImplemented.NOT_IMPLEMENTED); } else { - Object type = (obj instanceof PythonBuiltinClassType) ? ctx.getCore().lookupType((PythonBuiltinClassType) obj) : obj; - saveGlobal(frame, boundaryCallData, ctx, pickler, type, null); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); } } - private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PPickler pickler, Object obj, Object name) { + protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); + } + + private void saveGlobal(VirtualFrame frame, PythonContext ctx, PPickler pickler, int proto, boolean fastMode, Object obj, Object name) { PickleState st = getGlobalState(ctx.getCore()); Object gName; if (name != null) { @@ -1854,11 +2343,11 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P Object module; try { - module = importModule(frame, boundaryCallData, moduleName); + module = importModule(frame, ctx, moduleName); } catch (PException e) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_IMPORT_OF_MODULE_S_FAILED, obj, moduleName); } - final Pair pair = getDeepAttribute(frame, getLookupAttrNode(), module, dottedPath); + final Pair pair = getDeepAttribute(frame, getLookupGlobalAttrNode(), module, dottedPath); if (pair == null) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_ATTR_LOOKUP_FAIL_S_S, obj, globalName, moduleName); } @@ -1869,17 +2358,12 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P } boolean genGlobal; - if (pickler.proto >= 2) { + if (proto >= 2) { genGlobal = false; // See whether this is in the extension registry, and if so generate an EXT opcode. - PTuple extensionKey; - Object codeObj; - long code; - byte[] pdata = new byte[5]; - int n; - - extensionKey = createTuple(moduleName, globalName); - codeObj = getDictItem(frame, st.extensionRegistry, extensionKey); + + PTuple extensionKey = createTuple(moduleName, globalName); + Object codeObj = getDictItem(frame, st.extensionRegistry, extensionKey); // The object is not registered in the extension registry. This is the most likely // code path. if (codeObj == null) { @@ -1892,58 +2376,45 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_EXT_CODE_P_NOT_AN_INT, obj, codeObj); } - code = asLong(frame, codeObj); + long code = asLong(frame, codeObj); if (code <= 0 || code > 0x7fffffffL) { throw raise(PicklingError, ErrorMessages.CANT_PICKLE_P_EXT_CODE_OO_RANGE, obj, code); } // Generate an EXT opcode if (code <= 0xff) { - pdata[0] = PickleUtils.OPCODE_EXT1; - pdata[1] = (byte) code; - n = 2; + pickler.writeByteOp(this, PickleUtils.OPCODE_EXT1, code); } else if (code <= 0xffff) { - pdata[0] = PickleUtils.OPCODE_EXT2; - pdata[1] = (byte) (code & 0xff); - pdata[2] = (byte) ((code >> 8) & 0xff); - n = 3; + pickler.writeShortOp(this, PickleUtils.OPCODE_EXT2, code); } else { - pdata[0] = PickleUtils.OPCODE_EXT4; - pdata[1] = (byte) (code & 0xff); - pdata[2] = (byte) ((code >> 8) & 0xff); - pdata[3] = (byte) ((code >> 16) & 0xff); - pdata[4] = (byte) ((code >> 24) & 0xff); - n = 5; + pickler.writeIntOp(this, PickleUtils.OPCODE_EXT4, code); } - - write(pickler, pdata, n); } } else { genGlobal = true; } if (genGlobal) { - byte[] encoded; TruffleString lastname = dottedPath[dottedPath.length - 1]; if (parent == module) { globalName = lastname; } - if (pickler.proto >= 4) { - save(frame, pickler, moduleName, 0); - save(frame, pickler, globalName, 0); - write(pickler, PickleUtils.OPCODE_STACK_GLOBAL); + if (proto >= 4) { + saveGlobalModuleName(frame, pickler, moduleName); + saveGlobalName(frame, pickler, globalName); + pickler.write(this, PickleUtils.OPCODE_STACK_GLOBAL); } else if (parent != module) { Object reduceValue = createTuple(st.getattr, createTuple(parent, lastname)); - saveReduce(frame, ctx, pickler, reduceValue, null); + saveReduce(frame, ctx, pickler, proto, fastMode, reduceValue, null); } else { // Generate a normal global opcode if we are using a pickle protocol < 4, or if // the object is not registered in the extension registry - write(pickler, PickleUtils.OPCODE_GLOBAL); + pickler.write(this, PickleUtils.OPCODE_GLOBAL); // For protocol < 3 and if the user didn't request against doing so, we convert // module names to the old 2.x module names. - if (pickler.proto < 3 && pickler.fixImports) { + if (proto < 3 && pickler.fixImports) { final Pair to2Mapping = get3to2Mapping(frame, ctx.getCore(), moduleName, globalName); moduleName = to2Mapping.getLeft(); globalName = to2Mapping.getRight(); @@ -1953,67 +2424,84 @@ private void saveGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P // module name and the global name using UTF-8. We do so only when we are using // the pickle protocol newer than version 3. This is to ensure compatibility // with older Unpickler running on Python 2.x. - TruffleString.Encoding encoding = (pickler.proto == 3) ? TruffleString.Encoding.UTF_8 : TruffleString.Encoding.US_ASCII; - encoded = PickleUtils.encodeStrict(moduleName, ensureTsSwitchEncodingNode(), encoding, ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - if (encoded == null) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); - } - write(pickler, encoded); - writeASCII(pickler, T_NEWLINE); - // Save the name of the module - encoded = PickleUtils.encodeStrict(globalName, ensureTsSwitchEncodingNode(), encoding, ensureTsCopyToByteArrayNode(), ensureTsGetCodeRangeNode()); - if (encoded == null) { - throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, pickler.proto); + if (proto >= 3) { + if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) == TruffleString.CodeRange.BROKEN || ensureTsGetCodeRangeNode().execute(globalName, + TS_ENCODING) == TruffleString.CodeRange.BROKEN) { + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); + } + pickler.writeUtf8(this, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, (byte) '\n'); + pickler.writeUtf8(this, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + } else { + if (ensureTsGetCodeRangeNode().execute(moduleName, TS_ENCODING) != TruffleString.CodeRange.ASCII || ensureTsGetCodeRangeNode().execute(globalName, + TS_ENCODING) != TruffleString.CodeRange.ASCII) { + throw raise(PicklingError, ErrorMessages.CANT_PICKLE_MODULE_S_USING_PROTO_D, moduleName, proto); + } + pickler.writeASCII(this, moduleName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); + pickler.write(this, (byte) '\n'); + pickler.writeASCII(this, globalName, ensureTsSwitchEncodingNode(), ensureTsCopyToByteArrayNode()); } - write(pickler, encoded); - writeASCII(pickler, T_NEWLINE); + pickler.write(this, (byte) '\n'); } // Memoize the object - memoPut(pickler, obj); + memoPut(pickler, proto, fastMode, obj); } } @Specialization void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSave, @Bind Node inliningTarget, - @Cached("createFor($node)") BoundaryCallData boundaryCallData, - @Cached("createFor($node)") InteropCallData interopCallData, - @Cached PyFloatAsDoubleNode asDoubleNode, @Cached CallNode callNode, - @Cached PyObjectCallMethodObjArgs callMethod) { + @Cached PyObjectCallMethodObjArgs callMethod, + @Cached InlinedIntValueProfile protoProfile, + @Cached InlinedConditionProfile fastModeProfile) { Object obj = objArg; + int proto = protoProfile.profile(inliningTarget, pickler.getProto()); + boolean fastMode = fastModeProfile.profile(inliningTarget, pickler.isFast()); opcodeBoundary(frame, pickler); // The extra pers_save argument is necessary to avoid calling save_pers() // on its returned object. if (persSave == 0 && pickler.persFunc != null) { - if (savePers(frame, pickler, obj)) { + if (savePers(frame, pickler, proto, obj)) { return; } } - final Object type = getClass(obj); - // The old cPickle had an optimization that used switch-case statement dispatching on - // the first letter of the type name. This has was removed since benchmarks shown that - // this optimization was actually slowing things down. - // Atom types; these aren't memoized, so don't check the memo. if (obj == PNone.NONE) { - saveNone(pickler, obj); + profileSeen(SEEN_NONE); + saveNone(pickler); + return; + } else if (obj instanceof Boolean value) { + profileSeen(SEEN_BOOLEAN); + saveBool(pickler, proto, value); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.Boolean)) { - saveBool(frame, pickler, obj); + } else if (obj instanceof Integer value) { + profileSeen(SEEN_INTEGER); + saveLong(pickler, proto, value); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PInt)) { - saveLong(frame, pickler, obj); + } else if (obj instanceof Long value) { + profileSeen(SEEN_LONG); + saveLong(pickler, proto, value); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFloat)) { - saveFloat(frame, pickler, obj, inliningTarget, asDoubleNode); + } else if (obj instanceof PInt value && PGuards.isBuiltinPInt(value)) { + profileSeen(SEEN_PINT); + saveLong(frame, pickler, proto, value); + return; + } else if (obj instanceof Double value) { + profileSeen(SEEN_DOUBLE); + saveFloat(pickler, proto, value); + return; + } else if (obj instanceof PFloat value && PGuards.isBuiltinPFloat(value)) { + profileSeen(SEEN_PFLOAT); + saveFloat(pickler, proto, value.getValue()); return; } // to avoid misses in memo for the class: if (obj instanceof PythonBuiltinClassType classType) { + profileSeen(SEEN_BUILTIN_CLASS_TYPE); obj = PythonContext.get(this).getCore().lookupType(classType); } @@ -2021,38 +2509,55 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // instead of pickling the object once again. int memoIndex = pickler.memo.get(obj); if (memoIndex != -1) { - memoGet(pickler, memoIndex); + memoGet(pickler, proto, memoIndex); return; } PythonContext ctx = PythonContext.get(this); - if (isBuiltinClass(type, PythonBuiltinClassType.PBytes)) { - saveBytes(frame, ctx, pickler, obj, interopCallData); + if (obj instanceof PBytes bytes && PGuards.isBuiltinBytes(bytes)) { + profileSeen(SEEN_BYTES); + saveBytes(frame, ctx, pickler, proto, fastMode, bytes); + return; + } else if (obj instanceof TruffleString string) { + profileSeen(SEEN_TRUFFLE_STRING); + saveUnicode(frame, pickler, proto, fastMode, string); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PString)) { - saveUnicode(frame, pickler, obj); + } else if (obj instanceof PString string && PGuards.isBuiltinPString(string)) { + profileSeen(SEEN_PSTRING); + saveUnicode(frame, pickler, proto, fastMode, string); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PDict)) { - saveDict(frame, inliningTarget, callMethod, pickler, obj); + } else if (obj instanceof PDict dict && PGuards.isBuiltinDict(dict)) { + profileSeen(SEEN_DICT); + saveDict(frame, inliningTarget, callMethod, pickler, proto, fastMode, dict); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PSet)) { - saveSet(frame, ctx, pickler, obj); + } else if (obj instanceof PSet set && PGuards.isBuiltinSet(set)) { + profileSeen(SEEN_SET); + saveSet(frame, ctx, pickler, proto, fastMode, set); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFrozenSet)) { - saveFrozenset(frame, ctx, pickler, obj); + } else if (obj instanceof PFrozenSet frozenSet && PGuards.isBuiltinFrozenSet(frozenSet)) { + profileSeen(SEEN_FROZENSET); + saveFrozenset(frame, ctx, pickler, proto, fastMode, frozenSet); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PList)) { - saveList(frame, pickler, obj); + } else if (obj instanceof PList list && PGuards.isBuiltinList(list)) { + profileSeen(SEEN_LIST); + saveList(frame, pickler, proto, fastMode, list); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PTuple)) { - saveTuple(frame, pickler, obj); + } else if (obj instanceof PTuple tuple && PGuards.isBuiltinTuple(tuple)) { + profileSeen(SEEN_TUPLE); + saveTuple(frame, pickler, proto, fastMode, tuple); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PByteArray)) { - saveBytearray(frame, inliningTarget, ctx, pickler, obj, interopCallData); + } else if (PGuards.isNativeObject(obj) && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PTuple)) { + profileSeen(SEEN_NATIVE_TUPLE); + saveNativeTuple(frame, pickler, proto, fastMode, obj); + return; + } else if (obj instanceof PByteArray byteArray && PGuards.isBuiltinByteArray(byteArray)) { + profileSeen(SEEN_BYTE_ARRAY); + saveBytearray(frame, inliningTarget, ctx, pickler, proto, fastMode, byteArray); return; } else if (obj instanceof PPickleBuffer buffer) { - savePicklebuffer(frame, pickler, buffer); + profileSeen(SEEN_PICKLE_BUFFER); + savePickleBuffer(frame, pickler, proto, fastMode, buffer); return; } @@ -2061,27 +2566,37 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa if (pickler.reducerOverride != null) { Object reduceValue = callNode.execute(frame, pickler.reducerOverride, obj); if (reduceValue != PNotImplemented.NOT_IMPLEMENTED) { - handleReduce(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + handleReduce(frame, ctx, pickler, proto, fastMode, obj, reduceValue); return; } } - if (isBuiltinClass(type, PythonBuiltinClassType.PythonClass)) { - saveType(frame, boundaryCallData, ctx, pickler, obj); + if (obj instanceof PythonManagedClass clazz && clazz.getPythonClass() == PythonBuiltinClassType.PythonClass) { + profileSeen(SEEN_MANAGED_CLASS); + saveType(frame, ctx, pickler, proto, fastMode, clazz); + return; + } else if (obj instanceof PythonNativeClass && isBuiltinClass(getClass(obj), PythonBuiltinClassType.PythonClass)) { + profileSeen(SEEN_NATIVE_CLASS); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; - } else if (isBuiltinClass(type, PythonBuiltinClassType.PFunction)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + } else if (obj instanceof PFunction) { + profileSeen(SEEN_FUNCTION); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } + profileSeen(SEEN_OBJECT); + // Get a reduction callable, and call it. This may come from self.dispatch_table, // copyreg.dispatch_table, the object's __reduce_ex__ method, or the object's __reduce__ // method. + Object type = getClass(obj); Object reduceFunc = null; if (pickler.dispatchTable == null) { PickleState state = getGlobalState(ctx.getCore()); reduceFunc = getDictItem(frame, state.dispatchTable, type); } else { + profileSeen(SEEN_CUSTOM_DISPATCH); try { reduceFunc = getItem(frame, pickler.dispatchTable, type); } catch (PException ex) { @@ -2091,9 +2606,11 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa Object reduceValue; if (reduceFunc != null) { + profileSeen(SEEN_REGISTERED_REDUCER); reduceValue = callNode.execute(frame, reduceFunc, obj); - } else if (isSubType(type, PythonBuiltinClassType.PythonClass)) { - saveGlobal(frame, boundaryCallData, ctx, pickler, obj, null); + } else if (isType(obj)) { + profileSeen(SEEN_TYPE); + saveGlobal(frame, ctx, pickler, proto, fastMode, obj, null); return; } else { // XXX: If the __reduce__ method is defined, __reduce_ex__ is automatically defined @@ -2105,11 +2622,13 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa // Check for a __reduce_ex__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE_EX__); if (reduceFunc != PNone.NO_VALUE) { - reduceValue = callNode.execute(frame, reduceFunc, pickler.proto); + profileSeen(SEEN_REDUCE_EX); + reduceValue = callNode.execute(frame, reduceFunc, proto); } else { // Check for a __reduce__ method. reduceFunc = lookupAttribute(frame, obj, T___REDUCE__); if (reduceFunc != PNone.NO_VALUE) { + profileSeen(SEEN_REDUCE); reduceValue = callNode.execute(frame, reduceFunc); } else { throw raise(PicklingError, ErrorMessages.CANNOT_PICKLE_P_P, type, obj); @@ -2117,18 +2636,37 @@ void saveGeneric(VirtualFrame frame, PPickler pickler, Object objArg, int persSa } } - handleReduce(frame, boundaryCallData, ctx, pickler, obj, reduceValue); + handleReduce(frame, ctx, pickler, proto, fastMode, obj, reduceValue); } } - public abstract static class DumpNode extends BasePickleWriteNode { + @GenerateInline(false) + public abstract static class FlushToFileNode extends Node { + public abstract void execute(VirtualFrame frame, PPickler pickler); + + @Specialization + public void flush(VirtualFrame frame, PPickler pickler, + @Bind PythonLanguage language, + @Cached CallNode callNode) { + assert pickler.write != null; + // This will commit the frame first + PBytes output = pickler.getString(language, true); + callNode.execute(frame, pickler.write, output); + } + } + + @GenerateInline(false) + public abstract static class DumpNode extends Node { + private static final TruffleString REDUCE_OVERRIDE = tsLiteral("reducer_override"); + public abstract void execute(VirtualFrame frame, PPickler pickler, Object obj); @Specialization public void dump(VirtualFrame frame, PPickler pickler, Object obj, - @Cached SaveNode saveNode) { + @Cached("create(0)") SaveNode saveNode, + @Cached PyObjectLookupAttr lookupAttrNode) { try { - final Object tmp = getLookupAttrNode().executeCached(frame, pickler, REDUCE_OVERRIDE); + final Object tmp = lookupAttrNode.execute(frame, this, pickler, REDUCE_OVERRIDE); if (tmp != PNone.NO_VALUE) { pickler.reducerOverride = tmp; } else { @@ -2137,12 +2675,11 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, if (pickler.proto >= 2) { assert pickler.proto <= 256; - byte[] header = new byte[]{PickleUtils.OPCODE_PROTO, (byte) pickler.proto}; try { - write(pickler, header, 2); + pickler.write(this, PickleUtils.OPCODE_PROTO, (byte) pickler.proto); } catch (Exception e) { - handleError(pickler); + SaveNode.handleError(pickler); throw e; } @@ -2152,7 +2689,7 @@ public void dump(VirtualFrame frame, PPickler pickler, Object obj, } saveNode.execute(frame, pickler, obj, 0); - write(pickler, PickleUtils.OPCODE_STOP); + pickler.write(this, PickleUtils.OPCODE_STOP); pickler.commitFrame(); } finally { pickler.framing = false; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java index 305f47cede..b70dc9e32c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PUnpickler.java @@ -111,12 +111,15 @@ import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.PICKLE_PROTOCOL_HIGHEST; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.PREFETCH; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.READ_WHOLE_LINE; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; +import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_PEEK; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_PERSISTENT_LOAD; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READ; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READINTO; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_METHOD_READLINE; import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.getValidIntString; +import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; import static com.oracle.graal.python.nodes.BuiltinNames.T_ADD; import static com.oracle.graal.python.nodes.BuiltinNames.T_APPEND; import static com.oracle.graal.python.nodes.BuiltinNames.T_EXTEND; @@ -126,11 +129,14 @@ import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SETSTATE__; import static com.oracle.graal.python.nodes.StringLiterals.T_ASCII_UPPERCASE; import static com.oracle.graal.python.nodes.StringLiterals.T_STRICT; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import org.graalvm.collections.Pair; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.buffer.BufferFlags; @@ -166,6 +172,7 @@ import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyObjectLookupAttr; +import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectSetAttrO; import com.oracle.graal.python.lib.PyObjectSetItem; import com.oracle.graal.python.lib.PyTupleCheckNode; @@ -174,7 +181,7 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.argument.keywords.ExpandKeywordStarargsNode; import com.oracle.graal.python.nodes.argument.positional.ExecutePositionalStarargsNode; -import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; +import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; @@ -183,10 +190,12 @@ import com.oracle.graal.python.util.NumericSupport; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -360,7 +369,7 @@ public Object memoGet(int idx) { } public void memoPut(int idx, Object value) { - if (idx >= memo.length) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.SLOWPATH_PROBABILITY, idx >= memo.length)) { resizeMemoList(idx * 2); assert idx < memo.length; } @@ -385,6 +394,7 @@ public HashingStorage copyMemoToHashingStorage(Node inliningTarget, HashingStora // frame not needed for integer key hashingStorage = setItem.execute(null, inliningTarget, hashingStorage, i, memo[i]); } + LoopNode.reportLoopCount(inliningTarget, memo.length); return hashingStorage; } @@ -394,6 +404,8 @@ public void clearMemo() { // inner nodes public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleNode { + @Child private CastToTruffleStringNode castToTruffleStringNode; + @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private PyMemoryViewFromObject memoryViewNode; @Child private MemoryViewBuiltins.ToReadonlyNode toReadonlyNode; @Child private PythonBufferAcquireLibrary bufferAcquireLibrary; @@ -403,9 +415,69 @@ public abstract static class BasePickleReadNode extends PicklerNodes.BasePickleN @Child private TruffleString.ParseIntNode tsParseIntNode; + @CompilationFinal private boolean seenFileRead; + // we only need the reference, doesn't matter that the object may not yet be fully // constructed - @SuppressWarnings("this-escape") private InteropCallData interopCallData = InteropCallData.createFor(this); + @SuppressWarnings("this-escape") private final InteropCallData interopCallData = InteropCallData.createFor(this); + + protected TruffleString castToString(Object value) { + if (castToTruffleStringNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + castToTruffleStringNode = insert(CastToTruffleStringNode.create()); + } + return castToTruffleStringNode.executeCached(value); + } + + private PyObjectReprAsTruffleStringNode getReprNode() { + if (reprNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + reprNode = insert(PyObjectReprAsTruffleStringNode.create()); + } + return reprNode; + } + + public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, boolean allowQualname) { + if (allowQualname) { + TruffleString[] dottedPath = getDottedPath(obj, name); + Pair result = getDeepAttribute(frame, getLookupGlobalAttrNode(), obj, dottedPath); + if (result != null) { + return result.getLeft(); + } else { + throw raise(AttributeError, ErrorMessages.CANT_GET_ATTRIBUTE_S_ON_S, name, getReprNode().execute(frame, null, obj)); + } + } else { + Object attr = getLookupGlobalAttrNode().execute(frame, obj, name); + if (attr == NO_VALUE) { + throw raise(TypeError, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, attr, name); + } + return attr; + } + } + + protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { + PickleState state = getGlobalState(core); + return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); + } + + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { + return findClass(frame, core, self, castToString(moduleName), castToString(globalName)); + } + + public Object findClass(VirtualFrame frame, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { + // Try to map the old names used in Python 2.x to the new ones used in Python 3.x. We do + // this only with old pickle protocols and when the user has not disabled the feature. + TruffleString mName = moduleName; + TruffleString gName = globalName; + if (self.getProto() < 3 && self.isFixImports()) { + final Pair to3Mapping = get2To3Mapping(frame, core, mName, gName); + mName = to3Mapping.getLeft(); + gName = to3Mapping.getRight(); + } + + Object module = importModule(frame, PythonContext.get(this), mName); + return getattribute(frame, module, gName, self.getProto() >= 4); + } protected TruffleString.ParseLongNode ensureTsParseLongNode() { if (tsParseLongNode == null) { @@ -532,19 +604,24 @@ protected int readFromFile(VirtualFrame frame, PUnpickler self, int n) { } protected byte read(VirtualFrame frame, PUnpickler self) { - return read(frame, self, 1).get(0); + int offset = read(frame, self, 1); + return self.inputBuffer[offset]; } - protected ByteArrayView read(VirtualFrame frame, PUnpickler self, int n) { - if (n <= self.inputLen - self.nextReadIdx) { - ByteArrayView bytesView = new ByteArrayView(self.inputBuffer, self.nextReadIdx); + protected int read(VirtualFrame frame, PUnpickler self, int n) { + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, n <= self.inputLen - self.nextReadIdx)) { + int offset = self.nextReadIdx; self.nextReadIdx += n; - return bytesView; + return offset; + } + if (!seenFileRead) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenFileRead = true; } return readImpl(frame, self, n); } - private ByteArrayView readImpl(VirtualFrame frame, PUnpickler self, int n) { + private int readImpl(VirtualFrame frame, PUnpickler self, int n) { int numRead; // TODO: when GR-24978 is completed we should use PY_SSIZE_T_MAX if (self.nextReadIdx > Integer.MAX_VALUE - 1) { @@ -561,7 +638,7 @@ private ByteArrayView readImpl(VirtualFrame frame, PUnpickler self, int n) { throw badReadLine(); } self.nextReadIdx = n; - return new ByteArrayView(self.inputBuffer); + return 0; } protected int readInto(VirtualFrame frame, PUnpickler self, byte[] buffer) { @@ -674,13 +751,84 @@ public abstract static class FindClassNode extends BasePickleReadNode { public abstract Object execute(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name); @Specialization - Object find(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name, - @Cached("createFor($node)") BoundaryCallData boundaryCallData) { - return findClass(frame, boundaryCallData, PythonContext.get(this).getCore(), unpickler, module, name); + Object find(VirtualFrame frame, PUnpickler unpickler, TruffleString module, TruffleString name) { + return findClass(frame, PythonContext.get(this).getCore(), unpickler, module, name); } } public abstract static class LoadNode extends BasePickleReadNode { + private static final int SEEN_NONE = 0; + private static final int SEEN_BININT = 1; + private static final int SEEN_BININT1 = 2; + private static final int SEEN_BININT2 = 3; + private static final int SEEN_INT = 4; + private static final int SEEN_LONG = 5; + private static final int SEEN_LONG1 = 6; + private static final int SEEN_LONG4 = 7; + private static final int SEEN_FLOAT = 8; + private static final int SEEN_BINFLOAT = 9; + private static final int SEEN_SHORT_BINBYTES = 10; + private static final int SEEN_BINBYTES = 11; + private static final int SEEN_BINBYTES8 = 12; + private static final int SEEN_BYTEARRAY8 = 13; + private static final int SEEN_NEXT_BUFFER = 14; + private static final int SEEN_READONLY_BUFFER = 15; + private static final int SEEN_SHORT_BINSTRING = 16; + private static final int SEEN_BINSTRING = 17; + private static final int SEEN_STRING = 18; + private static final int SEEN_UNICODE = 19; + private static final int SEEN_SHORT_BINUNICODE = 20; + private static final int SEEN_BINUNICODE = 21; + private static final int SEEN_BINUNICODE8 = 22; + private static final int SEEN_EMPTY_TUPLE = 23; + private static final int SEEN_TUPLE1 = 24; + private static final int SEEN_TUPLE2 = 25; + private static final int SEEN_TUPLE3 = 26; + private static final int SEEN_TUPLE = 27; + private static final int SEEN_EMPTY_LIST = 28; + private static final int SEEN_LIST = 29; + private static final int SEEN_EMPTY_DICT = 30; + private static final int SEEN_DICT = 31; + private static final int SEEN_EMPTY_SET = 32; + private static final int SEEN_ADDITEMS = 33; + private static final int SEEN_FROZENSET = 34; + private static final int SEEN_OBJ = 35; + private static final int SEEN_INST = 36; + private static final int SEEN_NEWOBJ = 37; + private static final int SEEN_NEWOBJ_EX = 38; + private static final int SEEN_GLOBAL = 39; + private static final int SEEN_STACK_GLOBAL = 40; + private static final int SEEN_APPEND = 41; + private static final int SEEN_APPENDS = 42; + private static final int SEEN_BUILD = 43; + private static final int SEEN_DUP = 44; + private static final int SEEN_BINGET = 45; + private static final int SEEN_LONG_BINGET = 46; + private static final int SEEN_GET = 47; + private static final int SEEN_MARK = 48; + private static final int SEEN_BINPUT = 49; + private static final int SEEN_LONG_BINPUT = 50; + private static final int SEEN_PUT = 51; + private static final int SEEN_MEMOIZE = 52; + private static final int SEEN_POP = 53; + private static final int SEEN_POP_MARK = 54; + private static final int SEEN_SETITEM = 55; + private static final int SEEN_SETITEMS = 56; + private static final int SEEN_PERSID = 57; + private static final int SEEN_BINPERSID = 58; + private static final int SEEN_REDUCE = 59; + private static final int SEEN_PROTO = 60; + private static final int SEEN_FRAME = 61; + private static final int SEEN_EXT1 = 62; + private static final int SEEN_EXT2 = 63; + private static final int SEEN_EXT4 = 64; + private static final int SEEN_NEWTRUE = 65; + private static final int SEEN_NEWFALSE = 66; + private static final int SEEN_STOP = 67; + + @CompilationFinal private long seenOpcodes0; + @CompilationFinal private long seenOpcodes1; + @Child private PData.PDataPushNode pDataPushNode; @Child private PData.PDataPopNode pDataPopNode; @Child private PData.PDataPopTupleNode pDataPopTupleNode; @@ -696,6 +844,22 @@ public abstract static class LoadNode extends BasePickleReadNode { public abstract Object execute(VirtualFrame frame, PUnpickler self); + private void profileSeen(int seen) { + if (seen < Long.SIZE) { + long mask = 1L << seen; + if ((seenOpcodes0 & mask) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenOpcodes0 |= mask; + } + } else { + long mask = 1L << (seen - Long.SIZE); + if ((seenOpcodes1 & mask) == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + seenOpcodes1 |= mask; + } + } + } + protected HashingStorageCopy ensureHashingStorageCopy() { if (hashCopy == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -720,12 +884,12 @@ protected boolean isTuple(Object object) { return tupleCheck.execute(object); } - protected Object longFromBytes(byte[] data, boolean littleEndian) { + protected Object longFromBytes(byte[] data, int offset, int length, boolean littleEndian) { if (pyLongFromByteArray == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); pyLongFromByteArray = insert(IntNodesFactory.PyLongFromByteArrayNodeGen.create()); } - return pyLongFromByteArray.executeCached(data, littleEndian, true); + return pyLongFromByteArray.executeCached(data, offset, length, littleEndian, true); } protected void setAttribute(VirtualFrame frame, Object object, Object key, Object value) { @@ -807,11 +971,11 @@ void loadNone(PUnpickler self) { pDataPush(self, PNone.NONE); } - private static long calcBinInt(ByteArrayView s, int nBytes) { + private static long calcBinInt(byte[] s, int offset, int nBytes) { long x = 0; for (int i = 0; i < nBytes; i++) { - x |= (long) s.getUnsigned(i) << (8 * i); + x |= (long) (s[offset + i] & 0xff) << (8 * i); } // Unlike BININT1 and BININT2, BININT (more accurately BININT4) is signed, so on a box @@ -824,7 +988,7 @@ private static long calcBinInt(ByteArrayView s, int nBytes) { return x; } - private int calcBinSize(ByteArrayView s, int nbytes) { + private int calcBinSize(byte[] s, int offset, int nbytes) { int i; int x = 0; int n = nbytes; @@ -834,7 +998,7 @@ private int calcBinSize(ByteArrayView s, int nbytes) { // Check for integer overflow. BINBYTES8 and BINUNICODE8 opcodes have 64-bit size // that can't be represented on 32-bit platform. for (i = Integer.BYTES; i < n; i++) { - if (s.get(i) != 0) { + if (s[offset + i] != 0) { throw raise(PythonBuiltinClassType.OverflowError); } } @@ -842,7 +1006,7 @@ private int calcBinSize(ByteArrayView s, int nbytes) { } for (i = 0; i < n; i++) { - x |= s.getUnsigned(i) << (8 * i); + x |= (s[offset + i] & 0xff) << (8 * i); } // TODO: GR-24978 check for PY_SSIZE_T_MAX (see: _cpickle.c:calc_binsize) @@ -853,24 +1017,24 @@ private int calcBinSize(ByteArrayView s, int nbytes) { return x; } - private void loadBinIntX(PUnpickler self, ByteArrayView s, int size) { - long x = calcBinInt(s, size); + private void loadBinIntX(PUnpickler self, int offset, int size) { + long x = calcBinInt(self.inputBuffer, offset, size); pDataPush(self, x); } private void loadBinInt(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 4); - loadBinIntX(self, s, 4); + int offset = read(frame, self, 4); + loadBinIntX(self, offset, 4); } private void loadBinInt1(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 1); - loadBinIntX(self, s, 1); + int offset = read(frame, self, 1); + loadBinIntX(self, offset, 1); } private void loadBinInt2(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 2); - loadBinIntX(self, s, 2); + int offset = read(frame, self, 2); + loadBinIntX(self, offset, 2); } private void loadInt(VirtualFrame frame, PUnpickler self) { @@ -920,8 +1084,8 @@ private void loadLong(VirtualFrame frame, PUnpickler self) { private void loadCountedLong(VirtualFrame frame, PUnpickler self, int n) { assert n == 1 || n == 4; int size = n; - final ByteArrayView nbytes = read(frame, self, size); - size = (int) calcBinInt(nbytes, size); + int sizeOffset = read(frame, self, size); + size = (int) calcBinInt(self.inputBuffer, sizeOffset, size); Object value; @@ -933,8 +1097,8 @@ private void loadCountedLong(VirtualFrame frame, PUnpickler self, int n) { value = 0L; } else { // Read the raw little-endian bytes and convert. - final ByteArrayView pdata = read(frame, self, size); - value = longFromBytes(pdata.getBytes(size), true); + int dataOffset = read(frame, self, size); + value = longFromBytes(self.inputBuffer, dataOffset, size, true); } pDataPush(self, value); } @@ -954,15 +1118,15 @@ private void loadFloat(VirtualFrame frame, PUnpickler self) { private void loadBinFloat(VirtualFrame frame, PUnpickler self) { Object value; - ByteArrayView s = read(frame, self, 8); + int offset = read(frame, self, 8); - value = NumericSupport.bigEndian().getDouble(s.getBytes(Double.BYTES), 0); + value = NumericSupport.bigEndian().getDouble(self.inputBuffer, offset); pDataPush(self, value); } private void loadCountedBinBytes(VirtualFrame frame, PUnpickler self, int nbytes) { - final ByteArrayView s = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int offset = read(frame, self, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINBYTES", Integer.MAX_VALUE); } @@ -975,8 +1139,8 @@ private void loadCountedBinBytes(VirtualFrame frame, PUnpickler self, int nbytes } private void loadCountedByteArray(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 8); - int size = calcBinSize(s, 8); + int offset = read(frame, self, 8); + int size = calcBinSize(self.inputBuffer, offset, 8); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BYTEARRAY8", Integer.MAX_VALUE); } @@ -1023,18 +1187,18 @@ private void loadReadOnlyBuffer(VirtualFrame frame, PUnpickler self) { private void loadCountedBinString(VirtualFrame frame, PUnpickler self, int nbytes) { Object obj; - ByteArrayView s = read(frame, self, nbytes); + int offset = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINSTRING", Integer.MAX_VALUE); } - s = read(frame, self, size); + offset = read(frame, self, size); // Convert Python 2.x strings to bytes if the *encoding* given to the Unpickler was // 'bytes'. Otherwise, convert them to unicode. - final PBytes bytes = PFactory.createBytes(PythonLanguage.get(this), s.getBytes(size), size); + final PBytes bytes = PFactory.createBytes(PythonLanguage.get(this), PythonUtils.arrayCopyOfRange(self.inputBuffer, offset, offset + size)); if (ensureTsEqualNode().execute(self.encoding, T_CODEC_BYTES, TS_ENCODING)) { obj = bytes; } else { @@ -1093,16 +1257,16 @@ private void loadUnicode(VirtualFrame frame, PUnpickler self) { private void loadBinCountedUnicode(VirtualFrame frame, PUnpickler self, int nbytes) { Object str; - ByteArrayView s = read(frame, self, nbytes); + int offset = read(frame, self, nbytes); - int size = calcBinSize(s, nbytes); + int size = calcBinSize(self.inputBuffer, offset, nbytes); if (size < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "BINUNICODE", Integer.MAX_VALUE); } - s = read(frame, self, size); + offset = read(frame, self, size); - str = decodeUTF8(frame, s, size, T_ERRORS_SURROGATEPASS); + str = decodeUTF8(frame, self.inputBuffer, offset, size, T_ERRORS_SURROGATEPASS); pDataPush(self, str); } @@ -1147,13 +1311,14 @@ private void loadDict(VirtualFrame frame, PUnpickler self) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.ODD_NR_ITEMS_FOR_S, "DICT"); } - HashingStorage storage = EmptyStorage.INSTANCE; + HashingStorage storage = PDict.createNewStorage((j - i) / 2); for (k = i + 1; k < j; k += 2) { key = self.stack.data[k - 1]; value = self.stack.data[k]; storage = setHashingStorageItem(frame, storage, key, value); } + LoopNode.reportLoopCount(this, (j - i) / 2); self.stack.clear(i); pDataPush(self, PFactory.createDict(PythonLanguage.get(this), storage)); } @@ -1233,7 +1398,7 @@ private void loadObj(VirtualFrame frame, Node inliningTarget, PUnpickler self, P pDataPush(self, obj); } - private void loadInst(VirtualFrame frame, Node inliningTarget, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self, PyObjectCallMethodObjArgs callMethod) { + private void loadInst(VirtualFrame frame, Node inliningTarget, PythonContext ctx, PUnpickler self, PyObjectCallMethodObjArgs callMethod) { Object cls = null; Object obj = null; int i = marker(self); @@ -1253,7 +1418,7 @@ private void loadInst(VirtualFrame frame, Node inliningTarget, BoundaryCallData throw badReadLine(); } Object className = decodeASCII(frame, s, s.length - 1, T_ERRORS_STRICT); - cls = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, className); + cls = findClass(frame, ctx.getCore(), self, moduleName, className); } assert cls != null; @@ -1353,7 +1518,7 @@ private void doAppend(VirtualFrame frame, PUnpickler self, int x) { } } - private void loadGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self) { + private void loadGlobal(VirtualFrame frame, PythonContext ctx, PUnpickler self) { Object global = null; TruffleString globalName; byte[] s = readLine(frame, self); @@ -1369,14 +1534,14 @@ private void loadGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, P } globalName = PickleUtils.decodeUTF8Strict(s, s.length - 1, ensureTsFromByteArray(), ensureTsSwitchEncodingNode()); if (globalName != null) { - global = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, globalName); + global = findClass(frame, ctx.getCore(), self, moduleName, globalName); } } pDataPush(self, global); } - private void loadStackGlobal(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self) { + private void loadStackGlobal(VirtualFrame frame, PythonContext ctx, PUnpickler self) { Object globalName = null; Object moduleName = null; try { @@ -1388,7 +1553,7 @@ private void loadStackGlobal(VirtualFrame frame, BoundaryCallData boundaryCallDa if (!PGuards.isString(moduleName) || !PGuards.isString(globalName)) { throw raise(PythonBuiltinClassType.UnpicklingError, ErrorMessages.S_REQ_STR, "STACK_GLOBAL"); } - Object global = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, globalName); + Object global = findClass(frame, ctx.getCore(), self, moduleName, globalName); pDataPush(self, global); } @@ -1497,8 +1662,8 @@ private void loadBinGet(VirtualFrame frame, PUnpickler self) { } private void loadLongBinGet(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 4); - int idx = calcBinSize(s, 4); + int offset = read(frame, self, 4); + int idx = calcBinSize(self.inputBuffer, offset, 4); Object value = self.memoGet(idx); if (value == null) { @@ -1557,13 +1722,13 @@ private void loadBinPut(VirtualFrame frame, PUnpickler self) { } private void loadLongBinPut(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 4); + int offset = read(frame, self, 4); if (self.stack.size <= self.stack.fence) { throw pDataStackRaiseUnderflow(self); } Object value = self.stack.data[self.stack.size - 1]; - int idx = calcBinSize(s, 4); + int idx = calcBinSize(self.inputBuffer, offset, 4); if (idx < 0) { throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.NEG_S_ARG, "LONG_BINPUT"); } @@ -1644,6 +1809,9 @@ private void doSetItems(VirtualFrame frame, PUnpickler self, int x) { Object dict = self.stack.data[x - 1]; final boolean isBuiltinDict = dict instanceof PDict pDict && PGuards.isBuiltinDict(pDict); + if (isBuiltinDict && ((PDict) dict).getDictStorage() == EmptyStorage.INSTANCE) { + ((PDict) dict).setDictStorage(PDict.createNewStorage((len - x) / 2)); + } for (i = x + 1; i < len; i += 2) { key = self.stack.data[i - 1]; value = self.stack.data[i]; @@ -1654,6 +1822,7 @@ private void doSetItems(VirtualFrame frame, PUnpickler self, int x) { } } + LoopNode.reportLoopCount(this, (len - x) / 2); self.stack.clear(x); } @@ -1715,9 +1884,9 @@ private void loadReduce(VirtualFrame frame, PUnpickler self) { } private void loadProto(VirtualFrame frame, PUnpickler self) { - final ByteArrayView s = read(frame, self, 1); + int offset = read(frame, self, 1); - int i = s.getUnsigned(0); + int i = self.inputBuffer[offset] & 0xff; if (i <= PICKLE_PROTOCOL_HIGHEST) { self.proto = i; return; @@ -1727,25 +1896,25 @@ private void loadProto(VirtualFrame frame, PUnpickler self) { } private void loadFrame(VirtualFrame frame, PUnpickler self) { - ByteArrayView s = read(frame, self, 8); + int offset = read(frame, self, 8); - int frameLen = calcBinSize(s, 8); + int frameLen = calcBinSize(self.inputBuffer, offset, 8); if (frameLen < 0) { throw raise(PythonBuiltinClassType.OverflowError, ErrorMessages.S_EXCEEDS_MAX_SIZE_N_BYTES, "FRAME", Integer.MAX_VALUE); } - s = read(frame, self, frameLen); + read(frame, self, frameLen); // Rewind to start of frame self.nextReadIdx -= frameLen; } - private void loadExtension(VirtualFrame frame, BoundaryCallData boundaryCallData, PythonContext ctx, PUnpickler self, int nbytes) { + private void loadExtension(VirtualFrame frame, PythonContext ctx, PUnpickler self, int nbytes) { assert (nbytes == 1 || nbytes == 2 || nbytes == 4); // the nbytes bytes after the opcode - ByteArrayView codebytes = read(frame, self, nbytes); + int codeOffset = read(frame, self, nbytes); // calc_binint returns long - long code = calcBinInt(codebytes, nbytes); + long code = calcBinInt(self.inputBuffer, codeOffset, nbytes); if (code <= 0) { // note that 0 is forbidden @@ -1786,7 +1955,7 @@ private void loadExtension(VirtualFrame frame, BoundaryCallData boundaryCallData } // Load the object. - obj = findClass(frame, boundaryCallData, ctx.getCore(), self, moduleName, className); + obj = findClass(frame, ctx.getCore(), self, moduleName, className); // Cache code -> obj. setDictItem(frame, st.extensionCache, code, obj); @@ -1800,7 +1969,6 @@ private void loadBool(PUnpickler self, boolean bool) { @Specialization public Object load(VirtualFrame frame, PUnpickler self, @Bind Node inliningTarget, - @Cached("createFor($node)") BoundaryCallData boundaryCallData, @Cached GetCachedTpSlotsNode getSlots, @Cached CallSlotTpNewNode callNew, @Cached ExecutePositionalStarargsNode expandArgs, @@ -1826,207 +1994,275 @@ public Object load(VirtualFrame frame, PUnpickler self, } switch (s) { case OPCODE_NONE: + profileSeen(SEEN_NONE); loadNone(self); continue; case OPCODE_BININT: + profileSeen(SEEN_BININT); loadBinInt(frame, self); continue; case OPCODE_BININT1: + profileSeen(SEEN_BININT1); loadBinInt1(frame, self); continue; case OPCODE_BININT2: + profileSeen(SEEN_BININT2); loadBinInt2(frame, self); continue; case OPCODE_INT: + profileSeen(SEEN_INT); loadInt(frame, self); continue; case OPCODE_LONG: + profileSeen(SEEN_LONG); loadLong(frame, self); continue; case OPCODE_LONG1: + profileSeen(SEEN_LONG1); loadCountedLong(frame, self, 1); continue; case OPCODE_LONG4: + profileSeen(SEEN_LONG4); loadCountedLong(frame, self, 4); continue; case OPCODE_FLOAT: + profileSeen(SEEN_FLOAT); loadFloat(frame, self); continue; case OPCODE_BINFLOAT: + profileSeen(SEEN_BINFLOAT); loadBinFloat(frame, self); continue; case OPCODE_SHORT_BINBYTES: + profileSeen(SEEN_SHORT_BINBYTES); loadCountedBinBytes(frame, self, 1); continue; case OPCODE_BINBYTES: + profileSeen(SEEN_BINBYTES); loadCountedBinBytes(frame, self, 4); continue; case OPCODE_BINBYTES8: + profileSeen(SEEN_BINBYTES8); loadCountedBinBytes(frame, self, 8); continue; case OPCODE_BYTEARRAY8: + profileSeen(SEEN_BYTEARRAY8); loadCountedByteArray(frame, self); continue; case OPCODE_NEXT_BUFFER: + profileSeen(SEEN_NEXT_BUFFER); loadNextBuffer(frame, self); continue; case OPCODE_READONLY_BUFFER: + profileSeen(SEEN_READONLY_BUFFER); loadReadOnlyBuffer(frame, self); continue; case OPCODE_SHORT_BINSTRING: + profileSeen(SEEN_SHORT_BINSTRING); loadCountedBinString(frame, self, 1); continue; case OPCODE_BINSTRING: + profileSeen(SEEN_BINSTRING); loadCountedBinString(frame, self, 4); continue; case OPCODE_STRING: + profileSeen(SEEN_STRING); loadString(frame, self); continue; case OPCODE_UNICODE: + profileSeen(SEEN_UNICODE); loadUnicode(frame, self); continue; case OPCODE_SHORT_BINUNICODE: + profileSeen(SEEN_SHORT_BINUNICODE); loadBinCountedUnicode(frame, self, 1); continue; case OPCODE_BINUNICODE: + profileSeen(SEEN_BINUNICODE); loadBinCountedUnicode(frame, self, 4); continue; case OPCODE_BINUNICODE8: + profileSeen(SEEN_BINUNICODE8); loadBinCountedUnicode(frame, self, 8); continue; case OPCODE_EMPTY_TUPLE: + profileSeen(SEEN_EMPTY_TUPLE); loadCountedTuple(self, 0); continue; case OPCODE_TUPLE1: + profileSeen(SEEN_TUPLE1); loadCountedTuple(self, 1); continue; case OPCODE_TUPLE2: + profileSeen(SEEN_TUPLE2); loadCountedTuple(self, 2); continue; case OPCODE_TUPLE3: + profileSeen(SEEN_TUPLE3); loadCountedTuple(self, 3); continue; case OPCODE_TUPLE: + profileSeen(SEEN_TUPLE); loadTuple(self); continue; case OPCODE_EMPTY_LIST: + profileSeen(SEEN_EMPTY_LIST); loadEmptyList(self); continue; case OPCODE_LIST: + profileSeen(SEEN_LIST); loadList(self); continue; case OPCODE_EMPTY_DICT: + profileSeen(SEEN_EMPTY_DICT); loadEmptyDict(self); continue; case OPCODE_DICT: + profileSeen(SEEN_DICT); loadDict(frame, self); continue; case OPCODE_EMPTY_SET: + profileSeen(SEEN_EMPTY_SET); loadEmptySet(self); continue; case OPCODE_ADDITEMS: + profileSeen(SEEN_ADDITEMS); loadAddItems(frame, self); continue; case OPCODE_FROZENSET: + profileSeen(SEEN_FROZENSET); loadFrozenSet(frame, self); continue; case OPCODE_OBJ: + profileSeen(SEEN_OBJ); loadObj(frame, inliningTarget, self, callMethod); continue; case OPCODE_INST: - loadInst(frame, inliningTarget, boundaryCallData, ctx, self, callMethod); + profileSeen(SEEN_INST); + loadInst(frame, inliningTarget, ctx, self, callMethod); continue; case OPCODE_NEWOBJ: + profileSeen(SEEN_NEWOBJ); loadNewObj(frame, inliningTarget, self, getSlots, callNew, expandArgs); continue; case OPCODE_NEWOBJ_EX: + profileSeen(SEEN_NEWOBJ_EX); loadNewObjEx(frame, inliningTarget, self, getSlots, callNew, expandArgs, expandKwargs); continue; case OPCODE_GLOBAL: - loadGlobal(frame, boundaryCallData, ctx, self); + profileSeen(SEEN_GLOBAL); + loadGlobal(frame, ctx, self); continue; case OPCODE_STACK_GLOBAL: - loadStackGlobal(frame, boundaryCallData, ctx, self); + profileSeen(SEEN_STACK_GLOBAL); + loadStackGlobal(frame, ctx, self); continue; case OPCODE_APPEND: + profileSeen(SEEN_APPEND); loadAppend(frame, self); continue; case OPCODE_APPENDS: + profileSeen(SEEN_APPENDS); loadAppends(frame, self); continue; case OPCODE_BUILD: + profileSeen(SEEN_BUILD); loadBuild(frame, self); continue; case OPCODE_DUP: + profileSeen(SEEN_DUP); loadDup(self); continue; case OPCODE_BINGET: + profileSeen(SEEN_BINGET); loadBinGet(frame, self); continue; case OPCODE_LONG_BINGET: + profileSeen(SEEN_LONG_BINGET); loadLongBinGet(frame, self); continue; case OPCODE_GET: + profileSeen(SEEN_GET); loadGet(frame, self); continue; case OPCODE_MARK: + profileSeen(SEEN_MARK); loadMark(self); continue; case OPCODE_BINPUT: + profileSeen(SEEN_BINPUT); loadBinPut(frame, self); continue; case OPCODE_LONG_BINPUT: + profileSeen(SEEN_LONG_BINPUT); loadLongBinPut(frame, self); continue; case OPCODE_PUT: + profileSeen(SEEN_PUT); loadPut(frame, self); continue; case OPCODE_MEMOIZE: + profileSeen(SEEN_MEMOIZE); loadMemoize(self); continue; case OPCODE_POP: + profileSeen(SEEN_POP); loadPop(self); continue; case OPCODE_POP_MARK: + profileSeen(SEEN_POP_MARK); loadPopMark(self); continue; case OPCODE_SETITEM: + profileSeen(SEEN_SETITEM); loadSetItem(frame, self); continue; case OPCODE_SETITEMS: + profileSeen(SEEN_SETITEMS); loadSetItems(frame, self); continue; case OPCODE_PERSID: + profileSeen(SEEN_PERSID); loadPersId(frame, self); continue; case OPCODE_BINPERSID: + profileSeen(SEEN_BINPERSID); loadBinPersId(frame, self); continue; case OPCODE_REDUCE: + profileSeen(SEEN_REDUCE); loadReduce(frame, self); continue; case OPCODE_PROTO: + profileSeen(SEEN_PROTO); loadProto(frame, self); continue; case OPCODE_FRAME: + profileSeen(SEEN_FRAME); loadFrame(frame, self); continue; case OPCODE_EXT1: - loadExtension(frame, boundaryCallData, ctx, self, 1); + profileSeen(SEEN_EXT1); + loadExtension(frame, ctx, self, 1); continue; case OPCODE_EXT2: - loadExtension(frame, boundaryCallData, ctx, self, 2); + profileSeen(SEEN_EXT2); + loadExtension(frame, ctx, self, 2); continue; case OPCODE_EXT4: - loadExtension(frame, boundaryCallData, ctx, self, 4); + profileSeen(SEEN_EXT4); + loadExtension(frame, ctx, self, 4); continue; case OPCODE_NEWTRUE: + profileSeen(SEEN_NEWTRUE); loadBool(self, true); continue; case OPCODE_NEWFALSE: + profileSeen(SEEN_NEWFALSE); loadBool(self, false); continue; case OPCODE_STOP: + profileSeen(SEEN_STOP); break; default: if (0x20 <= s && s <= 0x7e && s != '\'' && s != '\\') { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java index 9b8518028a..539038ee45 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -63,6 +63,8 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateNodeFactory; @@ -80,6 +82,60 @@ protected List> getNodeFa return PickleModuleBuiltinsFactory.getFactories(); } + /** Learns the capacities reached by successful calls at one builtin node. */ + private static final class PicklerSizeProfile { + private static final int SHIFT = 3; + private static final long MAX_ESTIMATE = (16L * 1024 * 1024) << SHIFT; + + @CompilationFinal private long outputEstimate = (long) PickleUtils.WRITE_BUF_SIZE << SHIFT; + @CompilationFinal private long memoEstimate = (long) MemoTable.INITIAL_CAPACITY << SHIFT; + + int outputCapacity() { + return (int) (outputEstimate >> SHIFT); + } + + int memoCapacity() { + int estimate = (int) (memoEstimate >> SHIFT); + return estimate <= MemoTable.INITIAL_CAPACITY ? MemoTable.INITIAL_CAPACITY : Integer.highestOneBit(estimate - 1) << 1; + } + + void report(PPickler pickler) { + if (CompilerDirectives.inInterpreter()) { + if (pickler.getMaxOutputLen() > outputCapacity()) { + outputEstimate = update(outputEstimate, pickler.getMaxOutputLen()); + } + int memoCapacity = pickler.getMemo().capacity(); + if (memoCapacity > (memoEstimate >> SHIFT)) { + memoEstimate = update(memoEstimate, memoCapacity); + } + } + } + + private static long update(long shiftedEstimate, int capacity) { + long estimate = shiftedEstimate >> SHIFT; + return Math.min(shiftedEstimate + capacity - estimate, MAX_ESTIMATE); + } + } + + abstract static class ProfiledPickleDumpNode extends PythonClinicBuiltinNode { + @CompilationFinal private PicklerSizeProfile sizes = new PicklerSizeProfile(); + + final PPickler createPickler(PythonLanguage language) { + return PFactory.createPickler(language, sizes.outputCapacity(), sizes.memoCapacity()); + } + + final void reportSizes(PPickler pickler) { + sizes.report(pickler); + } + + @Override + public Node copy() { + ProfiledPickleDumpNode copy = (ProfiledPickleDumpNode) super.copy(); + copy.sizes = new PicklerSizeProfile(); + return copy; + } + } + @Override public void postInitialize(Python3Core core) { super.postInitialize(core); @@ -95,26 +151,27 @@ public void postInitialize(Python3Core core) { @ArgumentClinic(name = "protocol", conversion = ArgumentClinic.ClinicConversion.Int, defaultValue = J_DEFAULT_PICKLE_PROTOCOL, useDefaultForNone = true) @ArgumentClinic(name = "fix_imports", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true") @GenerateNodeFactory - abstract static class PickleDumpNode extends PythonClinicBuiltinNode { + abstract static class PickleDumpNode extends ProfiledPickleDumpNode { @Override protected ArgumentClinicProvider getArgumentClinic() { return PickleModuleBuiltinsClinicProviders.PickleDumpNodeClinicProviderGen.INSTANCE; } @Specialization - static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, Object file, int protocol, boolean fixImports, Object bufferCallback, + Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, Object file, int protocol, boolean fixImports, Object bufferCallback, @Bind Node inliningTarget, @Bind PythonLanguage language, @Cached PPickler.DumpNode dumpNode, @Cached PPickler.FlushToFileNode flushToFileNode, @Cached PyObjectLookupAttr lookup, @Cached PRaiseNode raiseNode) { - PPickler pickler = PFactory.createPickler(language); + PPickler pickler = createPickler(language); pickler.setProtocol(inliningTarget, raiseNode, protocol, fixImports); pickler.setOutputStream(frame, inliningTarget, raiseNode, lookup, file); pickler.setBufferCallback(inliningTarget, raiseNode, bufferCallback); dumpNode.execute(frame, pickler, obj); flushToFileNode.execute(frame, pickler); + reportSizes(pickler); return PNone.NONE; } } @@ -125,23 +182,25 @@ static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule @ArgumentClinic(name = "protocol", conversion = ArgumentClinic.ClinicConversion.Int, defaultValue = J_DEFAULT_PICKLE_PROTOCOL, useDefaultForNone = true) @ArgumentClinic(name = "fix_imports", conversion = ArgumentClinic.ClinicConversion.Boolean, defaultValue = "true") @GenerateNodeFactory - abstract static class PickleDumpsNode extends PythonClinicBuiltinNode { + abstract static class PickleDumpsNode extends ProfiledPickleDumpNode { @Override protected ArgumentClinicProvider getArgumentClinic() { return PickleModuleBuiltinsClinicProviders.PickleDumpsNodeClinicProviderGen.INSTANCE; } @Specialization - static Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, int protocol, boolean fixImports, Object bufferCallback, + Object dump(VirtualFrame frame, @SuppressWarnings("unused") PythonModule self, Object obj, int protocol, boolean fixImports, Object bufferCallback, @Bind Node inliningTarget, @Bind PythonLanguage language, @Cached PPickler.DumpNode dumpNode, @Cached PRaiseNode raiseNode) { - PPickler pickler = PFactory.createPickler(language); + PPickler pickler = createPickler(language); pickler.setProtocol(inliningTarget, raiseNode, protocol, fixImports); pickler.setBufferCallback(inliningTarget, raiseNode, bufferCallback); dumpNode.execute(frame, pickler, obj); - return pickler.getString(language); + Object result = pickler.getString(language, false); + reportSizes(pickler); + return result; } } @@ -198,8 +257,8 @@ static Object loads(VirtualFrame frame, @SuppressWarnings("unused") PythonModule @Cached PyObjectGetIter getIter) { try { PUnpickler unpickler = PFactory.createUnpickler(language); - byte[] data = bufferLib.getCopiedByteArray(buffer); - unpickler.setStringInput(data, data.length); + byte[] data = bufferLib.getInternalOrCopiedByteArray(buffer); + unpickler.setStringInput(data, bufferLib.getBufferLength(buffer)); unpickler.setInputEncoding(encoding, errors); unpickler.setBuffers(frame, inliningTarget, getIter, buffers); unpickler.setFixImports(fixImports); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java index 276a5c3d0c..feb9b8f210 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PickleUtils.java @@ -40,7 +40,6 @@ */ package com.oracle.graal.python.builtins.modules.pickle; -import static com.oracle.graal.python.builtins.modules.pickle.PPickler.BasePickleWriteNode.NEW_LINE_BYTE; import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; @@ -53,8 +52,6 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; -import com.oracle.graal.python.builtins.objects.bytes.ByteArrayBuffer; -import com.oracle.graal.python.builtins.objects.bytes.BytesUtils; import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod; import com.oracle.graal.python.builtins.objects.method.PMethod; import com.oracle.graal.python.builtins.objects.str.StringUtils; @@ -62,10 +59,9 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.StringLiterals; import com.oracle.graal.python.runtime.object.PFactory; -import com.oracle.graal.python.util.PythonUtils; +import com.oracle.graal.python.util.NumericSupport; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -218,37 +214,8 @@ public final class PickleUtils { public static final TruffleString T_PROTO_LE2_TRUE = tsLiteral("I01\n"); public static final TruffleString T_PROTO_LE2_FALSE = tsLiteral("I00\n"); - @ExplodeLoop public static void writeSize64(byte[] out, int start, int value) { - final int sizeofSizeT = Integer.BYTES; - for (int i = 0; i < sizeofSizeT; i++) { - out[start + i] = (byte) ((value >> (8 * i)) & 0xff); - } - for (int i = sizeofSizeT; i < 8; i++) { - out[start + i] = 0; - } - } - - public static byte[] resize(byte[] src, int newSize) { - byte[] newBytes = new byte[newSize]; - if (src != null) { - PythonUtils.arraycopy(src, 0, newBytes, 0, Math.min(newSize, src.length)); - } - return newBytes; - } - - private static int arrayCopyWithNewLine(byte[] dst, int offset, byte[] src) { - PythonUtils.arraycopy(src, 0, dst, offset, src.length); - int len = src.length + 2; - dst[len - 1] = NEW_LINE_BYTE; - return len; - } - - public static int toAsciiBytesWithNewLine(byte[] dst, int offset, long value, TruffleString.FromLongNode fromLongNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString s = fromLongNode.execute(value, TruffleString.Encoding.US_ASCII, true); - byte[] buf = new byte[s.byteLength(TruffleString.Encoding.US_ASCII)]; - copyToByteArrayNode.execute(s, 0, buf, 0, buf.length, TruffleString.Encoding.US_ASCII); - return arrayCopyWithNewLine(dst, offset, buf); + NumericSupport.littleEndian().putLong(out, start, Integer.toUnsignedLong(value)); } public static int getStringSize(byte[] bytes) { @@ -295,23 +262,6 @@ public static double asciiBytesToDouble(Node node, byte[] bytes, PythonBuiltinCl } } - public static byte[] encodeUTF8Strict(TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode, - TruffleString.GetCodeRangeNode getCodeRangeNode) { - return encodeStrict(str, switchEncodingNode, TruffleString.Encoding.UTF_8, copyToByteArrayNode, getCodeRangeNode); - } - - public static byte[] encodeStrict(TruffleString ts, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.Encoding encoding, TruffleString.CopyToByteArrayNode copyToByteArrayNode, - TruffleString.GetCodeRangeNode getCodeRangeNode) { - // TODO: [GR-39571] TruffleStrings: allow preservation of UTF-16 surrogate - if (getCodeRangeNode.execute(ts, TS_ENCODING) == TruffleString.CodeRange.BROKEN) { - return null; - } - TruffleString s = switchEncodingNode.execute(ts, encoding); - byte[] buf = new byte[s.byteLength(encoding)]; - copyToByteArrayNode.execute(s, 0, buf, 0, buf.length, encoding); - return buf; - } - public static TruffleString decodeUTF8Strict(byte[] data, int len, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingNode) { return decodeStrict(data, len, fromByteArrayNode, TruffleString.Encoding.UTF_8, switchEncodingNode); } @@ -326,39 +276,6 @@ private static TruffleString decodeStrict(byte[] data, int len, TruffleString.Fr return switchEncodingNode.execute(ret, TS_ENCODING); } - public static byte[] rawUnicodeEscape(TruffleString unicode, TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexUTF32Node codePointAtIndexNode) { - int len = codePointLengthNode.execute(unicode, TS_ENCODING); - ByteArrayBuffer buffer = new ByteArrayBuffer(len); - for (int i = 0; i < len; i++) { - final int ch = codePointAtIndexNode.execute(unicode, i); - if (ch >= 0x10000) { - // Map 32-bit characters to \Uxxxxxxxx - buffer.append('\\'); - buffer.append('U'); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 28) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 24) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 20) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 16) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 12) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 8) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 4) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[ch & 15]); - } else if (ch >= 256 || ch == '\\' || ch == 0 || ch == '\n' || ch == '\r' || ch == 0x1a) { - // Map 16-bit characters, \\ and \n to \Uxxxx - buffer.append('\\'); - buffer.append('u'); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 12) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 8) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[(ch >> 4) & 0xf]); - buffer.append((char) BytesUtils.HEXDIGITS[ch & 15]); - } else { - // Copy everything else as-is - buffer.append((char) ch); - } - } - return buffer.getByteArray(); - } - public static Pair initMethodRef(VirtualFrame frame, Node inliningTarget, PyObjectLookupAttr lookup, Object receiver, TruffleString identifier) { final Object func = lookup.execute(frame, inliningTarget, receiver, identifier); if (func == PNone.NO_VALUE) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java index 9b5ad2622f..5d8ea60e57 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerMemoProxyBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -53,7 +53,6 @@ import com.oracle.graal.python.builtins.CoreFunctions; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; -import com.oracle.graal.python.builtins.modules.pickle.MemoTable.MemoIterator; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.tuple.PTuple; @@ -106,11 +105,12 @@ Object clear(PPicklerMemoProxy self) { public static PDict picklerMemoCopyImpl(MemoTable memoTable) { PythonLanguage language = PythonLanguage.get(null); LinkedHashMap copy = new LinkedHashMap<>(); - MemoIterator iterator = memoTable.iterator(); - while (iterator.advance()) { - copy.put(System.identityHashCode(iterator.key()), - PFactory.createTuple(language, new Object[]{iterator.value(), iterator.key()})); - + for (int i = 0; i < memoTable.capacity(); i++) { + Object key = memoTable.getKeyAt(i); + if (key != null) { + copy.put(System.identityHashCode(key), + PFactory.createTuple(language, new Object[]{memoTable.getValueAt(i), key})); + } } return PFactory.createDictFromMapGeneric(language, copy); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java index 6e38abab05..3815619a8d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/pickle/PicklerNodes.java @@ -40,19 +40,11 @@ */ package com.oracle.graal.python.builtins.modules.pickle; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_NAME_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_IMPORT_MAPPING; -import static com.oracle.graal.python.builtins.modules.pickle.PickleUtils.T_CP_REVERSE_NAME_MAPPING; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; -import static com.oracle.graal.python.nodes.BuiltinNames.T___MAIN__; -import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_STR_NOT_P; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___CLASS__; -import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; -import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.nodes.StringLiterals.T_UTF8; -import static com.oracle.graal.python.nodes.statement.AbstractImportNode.importModule; import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError; +import static com.oracle.graal.python.runtime.exception.PythonErrorType.KeyError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -78,7 +70,7 @@ import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.function.PKeyword; -import com.oracle.graal.python.builtins.objects.str.StringUtils; +import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyIterCheckNode; import com.oracle.graal.python.lib.PyIterNextNode; @@ -86,7 +78,6 @@ import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.PyObjectGetItem; import com.oracle.graal.python.lib.PyObjectLookupAttr; -import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; import com.oracle.graal.python.lib.PyObjectSetItem; import com.oracle.graal.python.lib.PyObjectSizeNode; import com.oracle.graal.python.nodes.ErrorMessages; @@ -100,24 +91,78 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.InlineIsBuiltinClassProfile; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.nodes.statement.AbstractImportNode.ImportName; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; -import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; +import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Exclusive; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; public final class PicklerNodes { + @GenerateInline(false) + abstract static class ImportModuleNode extends Node { + abstract PythonModule execute(VirtualFrame frame, PythonContext context, TruffleString name); + + @Specialization + static PythonModule doImport(VirtualFrame frame, PythonContext context, TruffleString name, + @Bind Node inliningTarget, + @Cached ImportName importNameNode, + @Cached CachedHashingStorageGetItem getItemNode, + @Cached PRaiseNode raiseNode) { + // ImportName checks initialization for cached modules and honors custom import hooks. + // With an empty fromlist, a dotted import returns the top-level package, so look up + // the requested module by its full name after importing for side effects. + importNameNode.execute(frame, context, context.getBuiltins(), name, PNone.NONE, PythonUtils.EMPTY_TRUFFLESTRING_ARRAY, 0); + Object module = getItemNode.execute(frame, context.getSysModules().getDictStorage(), name); + if (module == null) { + throw raiseNode.raise(inliningTarget, KeyError, new Object[]{name}); + } + if (module instanceof PythonModule pythonModule) { + return pythonModule; + } + throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.NotImplementedError, ErrorMessages.PUTTING_NON_MODULE_OBJECTS_IN_SYS_MODULES_IS_NOT_SUPPORTED); + } + } + + @GenerateInline(false) + @ImportStatic(PythonUtils.class) + abstract static class LookupGlobalAttributeNode extends Node { + abstract Object execute(VirtualFrame frame, Object receiver, TruffleString name); + + // Unpickling decodes fresh strings. Give attribute lookup a stable name identity without + // caching the attribute value or interning arbitrary pickle contents. + @Specialization(guards = "equal.execute(name, cachedName, TS_ENCODING)", limit = "3") + static Object cached(VirtualFrame frame, Object receiver, TruffleString name, + @Cached("name") TruffleString cachedName, + @Cached TruffleString.EqualNode equal, + @Exclusive @Cached(inline = false) PyObjectLookupAttr lookup) { + return lookup.executeCached(frame, receiver, cachedName); + } + + @Specialization(replaces = "cached") + static Object generic(VirtualFrame frame, Object receiver, TruffleString name, + @Exclusive @Cached(inline = false) PyObjectLookupAttr lookup) { + return lookup.executeCached(frame, receiver, name); + } + } + abstract static class BasePickleNode extends Node { private static final TruffleString T_LOCALS = tsLiteral(""); - static final TruffleString T_SYS_MODULES = tsLiteral("sys.modules"); public static final TruffleString T_CODEC_RAW_UNICODE_ESCAPE = tsLiteral("raw_unicode_escape"); public static final TruffleString T_CODEC_BYTES = tsLiteral("bytes"); public static final TruffleString T_CODEC_ASCII = tsLiteral("ascii"); @@ -134,9 +179,8 @@ abstract static class BasePickleNode extends Node { @Child private HashingStorageSetItem setHashingStorageItemNode; @Child private PyObjectSetItem pyObjectSetItemNode; @Child private CachedHashingStorageGetItem getHashingStorageItemNode; - @Child private SequenceStorageNodes.GetItemNode getSeqStorageItemNode; + @Child private SequenceStorageNodes.GetItemScalarNode getSeqStorageItemNode; @Child private PyNumberAsSizeNode asSizeNode; - @Child private CastToTruffleStringNode castToTruffleStringNode; @Child private SequenceNodes.GetSequenceStorageNode getSequenceStorageNode; @Child private CallNode callNode; @Child private ExecutePositionalStarargsNode getArgsNode; @@ -149,24 +193,22 @@ abstract static class BasePickleNode extends Node { @Child private GetClassNode getClassNode; @Child private PyObjectSizeNode sizeNode; @Child private PyObjectLookupAttr lookupAttrNode; + @Child private LookupGlobalAttributeNode lookupGlobalAttrNode; + @Child private ImportModuleNode importModuleNode; @Child private BytesNodes.ToBytesNode toBytesNode; - @Child private PyObjectReprAsTruffleStringNode reprNode; @Child private TruffleString.FromByteArrayNode tsFromByteArrayNode; @Child private TruffleString.FromByteArrayWithCompactionUTF32Node tsFromByteArrayWithCompactionNode; @Child private TruffleString.CodePointLengthNode tsCodePointLengthNode; - @Child private TruffleString.CodePointAtIndexUTF32Node tsCodePointAtIndexUTF32Node; - @Child private TruffleString.FromLongNode tsFromLongNode; - @Child private TruffleString.IndexOfStringNode tsIndexOfStringNode; + @Child private TruffleString.IndexOfCodePointNode tsIndexOfCodePointNode; @Child private TruffleString.SubstringNode tsSubstringNode; @Child private TruffleString.EqualNode tsEqualNode; - @Child private TruffleString.CopyToByteArrayNode tsCopyToByteArrayNode; - @Child private TruffleString.GetCodeRangeNode tsGetCodeRangeNode; @Child private TruffleString.SwitchEncodingNode tsSwitchEncodingNode; + @Child private TruffleString.IsValidNode tsIsValidNode; @Child private HashingStorageGetIterator getHashingStorageIteratorNode; @Child private HashingStorageIteratorNext hashingStorageItNext; @Child private HashingStorageIteratorKey hashingStorageItKey; @Child private HashingStorageIteratorValue hashingStorageItValue; - private final BranchProfile errorProfile = BranchProfile.create(); + protected final BranchProfile errorProfile = BranchProfile.create(); protected PException raise(PythonBuiltinClassType type, TruffleString string) { errorProfile.enter(); @@ -207,28 +249,12 @@ protected TruffleString.CodePointLengthNode ensureTsCodePointLengthNode() { return tsCodePointLengthNode; } - protected TruffleString.CodePointAtIndexUTF32Node ensureTsCodePointAtIndexUTF32Node() { - if (tsCodePointAtIndexUTF32Node == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsCodePointAtIndexUTF32Node = insert(TruffleString.CodePointAtIndexUTF32Node.create()); - } - return tsCodePointAtIndexUTF32Node; - } - - protected TruffleString.FromLongNode ensureTsFromLongNode() { - if (tsFromLongNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsFromLongNode = insert(TruffleString.FromLongNode.create()); - } - return tsFromLongNode; - } - - protected TruffleString.IndexOfStringNode ensureTsIndexOfStringNode() { - if (tsIndexOfStringNode == null) { + protected TruffleString.IndexOfCodePointNode ensureTsIndexOfCodePointNode() { + if (tsIndexOfCodePointNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - tsIndexOfStringNode = insert(TruffleString.IndexOfStringNode.create()); + tsIndexOfCodePointNode = insert(TruffleString.IndexOfCodePointNode.create()); } - return tsIndexOfStringNode; + return tsIndexOfCodePointNode; } protected TruffleString.SubstringNode ensureTsSubstringNode() { @@ -247,22 +273,6 @@ protected TruffleString.EqualNode ensureTsEqualNode() { return tsEqualNode; } - protected TruffleString.CopyToByteArrayNode ensureTsCopyToByteArrayNode() { - if (tsCopyToByteArrayNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsCopyToByteArrayNode = insert(TruffleString.CopyToByteArrayNode.create()); - } - return tsCopyToByteArrayNode; - } - - protected TruffleString.GetCodeRangeNode ensureTsGetCodeRangeNode() { - if (tsGetCodeRangeNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - tsGetCodeRangeNode = insert(TruffleString.GetCodeRangeNode.create()); - } - return tsGetCodeRangeNode; - } - protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { if (tsSwitchEncodingNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -271,20 +281,20 @@ protected TruffleString.SwitchEncodingNode ensureTsSwitchEncodingNode() { return tsSwitchEncodingNode; } - protected byte[] toBytes(VirtualFrame frame, Object obj) { - if (toBytesNode == null) { + protected TruffleString.IsValidNode ensureTsIsValidNode() { + if (tsIsValidNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - toBytesNode = insert(BytesNodes.ToBytesNode.create()); + tsIsValidNode = insert(TruffleString.IsValidNode.create()); } - return toBytesNode.execute(frame, obj); + return tsIsValidNode; } - private PyObjectReprAsTruffleStringNode getReprNode() { - if (reprNode == null) { + protected byte[] toBytes(VirtualFrame frame, Object obj) { + if (toBytesNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - reprNode = insert(PyObjectReprAsTruffleStringNode.create()); + toBytesNode = insert(BytesNodes.ToBytesNode.create()); } - return reprNode; + return toBytesNode.execute(frame, obj); } protected HashingStorageIterator getHashingStorageIterator(HashingStorage s) { @@ -295,6 +305,14 @@ protected HashingStorageIterator getHashingStorageIterator(HashingStorage s) { return getHashingStorageIteratorNode.executeCached(s); } + protected PythonModule importModule(VirtualFrame frame, PythonContext context, TruffleString name) { + if (importModuleNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + importModuleNode = insert(PicklerNodesFactory.ImportModuleNodeGen.create()); + } + return importModuleNode.execute(frame, context, name); + } + protected HashingStorageIteratorNext ensureHashingStorageIteratorNext() { if (hashingStorageItNext == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -367,8 +385,12 @@ protected Object decodeASCII(VirtualFrame frame, byte[] bytes, int len, TruffleS return decode(frame, PFactory.createBytes(PythonLanguage.get(this), bytes, len), T_CODEC_ASCII, errors); } - protected Object decodeUTF8(VirtualFrame frame, ByteArrayView bytes, int len, TruffleString errors) { - return decode(frame, PFactory.createBytes(PythonLanguage.get(this), bytes.getBytes(len), len), T_UTF8, errors); + protected Object decodeUTF8(VirtualFrame frame, byte[] bytes, int offset, int len, TruffleString errors) { + TruffleString utf8 = ensureTsFromByteArray().execute(bytes, offset, len, TruffleString.Encoding.UTF_8, true); + if (ensureTsIsValidNode().execute(utf8, TruffleString.Encoding.UTF_8)) { + return ensureTsSwitchEncodingNode().execute(utf8, TS_ENCODING); + } + return decode(frame, PFactory.createBytes(PythonLanguage.get(this), PythonUtils.arrayCopyOfRange(bytes, offset, offset + len)), T_UTF8, errors); } protected Object decode(VirtualFrame frame, Object value, TruffleString encoding) { @@ -427,6 +449,14 @@ protected PyObjectLookupAttr getLookupAttrNode() { return lookupAttrNode; } + protected LookupGlobalAttributeNode getLookupGlobalAttrNode() { + if (lookupGlobalAttrNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + lookupGlobalAttrNode = insert(PicklerNodesFactory.LookupGlobalAttributeNodeGen.create()); + } + return lookupGlobalAttrNode; + } + protected Object lookupAttribute(Frame frame, Object receiver, TruffleString name) { return getLookupAttrNode().executeCached(frame, receiver, name); } @@ -476,14 +506,6 @@ protected SequenceStorage getSequenceStorage(Object iterator) { return getSequenceStorageNode.executeCached(iterator); } - protected TruffleString castToString(Object value) { - if (castToTruffleStringNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - castToTruffleStringNode = insert(CastToTruffleStringNode.create()); - } - return castToTruffleStringNode.executeCached(value); - } - public int asSizeExact(VirtualFrame frame, Object pyNumber) { if (asSizeNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -555,12 +577,12 @@ public Object getNextItem(VirtualFrame frame, Object iterator) { return getNextNode.executeCached(frame, iterator); } - public Object getItem(VirtualFrame frame, SequenceStorage storage, int i) { + public Object getItem(SequenceStorage storage, int i) { if (getSeqStorageItemNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemNode.create()); + getSeqStorageItemNode = insert(SequenceStorageNodes.GetItemScalarNode.create()); } - return getSeqStorageItemNode.execute(frame, storage, i); + return getSeqStorageItemNode.executeCached(storage, i); } public Object getItem(VirtualFrame frame, Object obj, Object slice) { @@ -586,36 +608,58 @@ public TruffleString asString(Object value) { } } - public TruffleString asStringStrict(Object value) { - if (value instanceof TruffleString) { - return (TruffleString) value; - } else { - try { - return toStringNode.executeCached(value); - } catch (CannotCastException e) { - throw raise(PythonBuiltinClassType.TypeError, MUST_BE_STR_NOT_P, value); - } - } - } - - public static Pair getDeepAttribute(VirtualFrame frame, PyObjectLookupAttr lookup, Object obj, TruffleString[] names) { + public static Pair getDeepAttribute(VirtualFrame frame, LookupGlobalAttributeNode lookup, Object obj, TruffleString[] names) { Object parent = null; Object object = obj; - for (TruffleString name : names) { + for (int i = 0; i < names.length; i++) { parent = object; - object = lookup.executeCached(frame, parent, name); + object = lookup.execute(frame, parent, names[i]); if (object == NO_VALUE) { + LoopNode.reportLoopCount(lookup, i); return null; } } + LoopNode.reportLoopCount(lookup, names.length); return Pair.create(object, parent); } + private TruffleString[] splitDottedPath(TruffleString name) { + int length = ensureTsCodePointLengthNode().execute(name, TS_ENCODING); + TruffleString.IndexOfCodePointNode indexOf = ensureTsIndexOfCodePointNode(); + int firstDot = length == 0 ? -1 : indexOf.execute(name, '.', 0, length, TS_ENCODING); + if (firstDot < 0) { + return new TruffleString[]{name}; + } + + // Count the components so that we can allocate the result without growing or copying it. + int parts = 2; + int start = firstDot + 1; + while (start < length) { + int dot = indexOf.execute(name, '.', start, length, TS_ENCODING); + if (dot < 0) { + break; + } + parts++; + start = dot + 1; + } + LoopNode.reportLoopCount(this, parts - 2 + (start < length ? 1 : 0)); + TruffleString[] dottedPath = new TruffleString[parts]; + TruffleString.SubstringNode substring = ensureTsSubstringNode(); + start = 0; + int part = 0; + for (int dot = firstDot; dot >= 0; dot = start < length ? indexOf.execute(name, '.', start, length, TS_ENCODING) : -1) { + dottedPath[part++] = substring.execute(name, start, dot - start, TS_ENCODING, false); + start = dot + 1; + } + LoopNode.reportLoopCount(this, part); + dottedPath[part] = substring.execute(name, start, length - start, TS_ENCODING, false); + return dottedPath; + } + public TruffleString[] getDottedPath(Object obj, TruffleString name) { - TruffleString[] dottedPath = StringUtils.split(name, T_DOT, ensureTsCodePointLengthNode(), ensureTsIndexOfStringNode(), ensureTsSubstringNode(), ensureTsEqualNode()); - assert dottedPath.length > 0; - for (TruffleString subPath : dottedPath) { - if (ensureTsEqualNode().execute(subPath, T_LOCALS, TS_ENCODING)) { + TruffleString[] dottedPath = splitDottedPath(name); + for (int i = 0; i < dottedPath.length; i++) { + if (ensureTsEqualNode().execute(dottedPath[i], T_LOCALS, TS_ENCODING)) { if (obj == null) { throw raise(AttributeError, ErrorMessages.CANT_PICKLE_LOCAL_OBJ_S, name); } else { @@ -623,43 +667,21 @@ public TruffleString[] getDottedPath(Object obj, TruffleString name) { } } } + LoopNode.reportLoopCount(this, dottedPath.length); return dottedPath; } - public Object getattribute(VirtualFrame frame, Object obj, TruffleString name, boolean allowQualname) { - if (allowQualname) { - TruffleString[] dottedPath = getDottedPath(obj, name); - Pair result = getDeepAttribute(frame, getLookupAttrNode(), obj, dottedPath); - if (result != null) { - return result.getLeft(); - } else { - throw raise(AttributeError, ErrorMessages.CANT_GET_ATTRIBUTE_S_ON_S, name, getReprNode().execute(frame, null, obj)); - } - } else { - return lookupAttributeStrict(frame, obj, name); - } - } - - protected Pair get3to2Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping3To2, state.importMapping3To2, T_CP_REVERSE_NAME_MAPPING, T_CP_REVERSE_IMPORT_MAPPING, moduleName, globalName); - } - - protected Pair get2To3Mapping(VirtualFrame frame, Python3Core core, TruffleString moduleName, TruffleString globalName) { - PickleState state = getGlobalState(core); - return getMapping(frame, state.nameMapping2To3, state.importMapping2To3, T_CP_NAME_MAPPING, T_CP_IMPORT_MAPPING, moduleName, globalName); - } - - private Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, + protected Pair getMapping(VirtualFrame frame, PDict nameMapping, PDict importMapping, TruffleString nameMappingLabel, TruffleString importMappingLabel, TruffleString moduleName, TruffleString globalName) { Object key = PFactory.createTuple(PythonLanguage.get(this), new Object[]{moduleName, globalName}); Object item = getDictItem(frame, nameMapping, key); if (item != null) { - if (!(item instanceof PTuple) || length(frame, item) != 2) { + if (!(item instanceof PTuple) || ((PTuple) item).getSequenceStorage().length() != 2) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P, nameMappingLabel, "2-tuples", item); } - Object mappedModuleName = getItem(frame, item, 0); - Object mappedGlobalName = getItem(frame, item, 1); + SequenceStorage storage = ((PTuple) item).getSequenceStorage(); + Object mappedModuleName = getItem(storage, 0); + Object mappedGlobalName = getItem(storage, 1); if (!PGuards.isString(mappedModuleName) || !PGuards.isString(mappedGlobalName)) { throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.S_SHOULD_BE_S_NOT_P_P, nameMappingLabel, "str", mappedModuleName, mappedGlobalName); } @@ -677,75 +699,5 @@ private Pair getMapping(VirtualFrame frame, PDict return Pair.create(moduleName, globalName); } - - public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, Python3Core core, PUnpickler self, Object moduleName, Object globalName) { - return findClass(frame, boundaryCallData, core, self, castToString(moduleName), castToString(globalName)); - } - - public Object findClass(VirtualFrame frame, BoundaryCallData boundaryCallData, Python3Core core, PUnpickler self, TruffleString moduleName, TruffleString globalName) { - // Try to map the old names used in Python 2.x to the new ones used in Python 3.x. We do - // this only with old pickle protocols and when the user has not disabled the feature. - TruffleString mName = moduleName; - TruffleString gName = globalName; - if (self.getProto() < 3 && self.isFixImports()) { - final Pair to3Mapping = get2To3Mapping(frame, core, mName, gName); - mName = to3Mapping.getLeft(); - gName = to3Mapping.getRight(); - } - - // we don't use PyImport_GetModule here, because it can return partially-initialised - // modules, which then cause the getattribute to fail. - Object module = importModule(frame, boundaryCallData, mName); - return getattribute(frame, module, gName, self.getProto() >= 4); - } - - private static boolean checkModule(VirtualFrame frame, PyObjectLookupAttr lookup, Object moduleName, Object module, Object global, TruffleString[] dottedPath) { - if (module == PNone.NONE) { - return false; - } - - assert !(moduleName instanceof String) : "moduleName shouldn't be j.l.String"; - - if (moduleName instanceof TruffleString && ((TruffleString) moduleName).equalsUncached(T___MAIN__, TS_ENCODING)) { - return false; - } - final Pair pair = getDeepAttribute(frame, lookup, module, dottedPath); - if (pair == null) { - return false; - } - return pair.getLeft() == global; - } - - public TruffleString whichModule(VirtualFrame frame, PythonContext context, Object global, TruffleString[] dottedPath) { - Object moduleName = lookupAttribute(frame, global, T___MODULE__); - if (moduleName != NO_VALUE) { - // In some rare cases (e.g., bound methods of extension types), __module__ can be - // None. If it is so, then search sys.modules for the module of global - if (moduleName != PNone.NONE) { - return asStringStrict(moduleName); - } - } - - // Fallback on walking sys.modules - final PDict sysModules = context.getSysModules(); - if (sysModules == null) { - throw raise(PythonBuiltinClassType.RuntimeError, ErrorMessages.UNABLE_TO_GET_S, T_SYS_MODULES); - } - - final HashingStorage storage = sysModules.getDictStorage(); - HashingStorageIterator it = getHashingStorageIterator(storage); - HashingStorageIteratorNext nextNode = ensureHashingStorageIteratorNext(); - HashingStorageIteratorKey getKeyNode = ensureHashingStorageIteratorKey(); - HashingStorageIteratorValue getValueNode = ensureHashingStorageIteratorValue(); - while (nextNode.executeCached(storage, it)) { - Object value = getValueNode.executeCached(storage, it); - Object key = getKeyNode.executeCached(storage, it); - if (checkModule(frame, getLookupAttrNode(), moduleName, value, global, dottedPath)) { - return asStringStrict(key); - } - } - // If no module is found, use __main__ - return T___MAIN__; - } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java index d166e20c21..e18592d60d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/MatchBuiltins.java @@ -84,6 +84,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -266,6 +267,7 @@ static Object expand(VirtualFrame frame, PMatch self, Object templateString, appendStringNode.execute(builder, substring); } } + LoopNode.reportLoopCount(inliningTarget, template.indices.length); // add the extra literal Object literal = template.literals[template.literals.length - 1]; @@ -309,6 +311,7 @@ static Object group(VirtualFrame frame, PMatch self, Object[] args, PKeyword[] k Object group = getSliceNode.execute(frame, inliningTarget, self, args[i]); groups[i] = group; } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createTuple(language, groups); } @@ -342,6 +345,7 @@ static Object groups(VirtualFrame frame, PMatch self, Object defaultValueArg, groups[i] = group; } } + LoopNode.reportLoopCount(inliningTarget, groups.length); return PFactory.createTuple(language, groups); } @@ -375,6 +379,7 @@ static Object groupDict(VirtualFrame frame, PMatch self, Object defaultValueArg, keysAndValues[i + 1] = group; } } + LoopNode.reportLoopCount(inliningTarget, keysAndValues.length / 2); LinkedHashMap groupNameToGroupMap = arrayToMap(keysAndValues); return PFactory.createDictFromMap(language, groupNameToGroupMap); @@ -553,6 +558,7 @@ static PTuple spans(PMatch self, spans[groupIndex] = PFactory.createTuple(language, new int[]{start, end}); } + LoopNode.reportLoopCount(inliningTarget, spans.length); return PFactory.createTuple(language, spans); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java index 7d0f041dc5..415432bd14 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/PatternBuiltins.java @@ -135,6 +135,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -808,6 +809,7 @@ static Object doString(Node inliningTarget, Object compiledRegex, Object compile pos = end; mustAdvance = start == end; } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) n * groupCount)); result.add(createSubstring(inliningTarget, input, binary, pos, stringLength, substringByteIndexNode, copyToByteArrayNode)); return PFactory.createList(PythonLanguage.get(inliningTarget), result.toObjectArray()); } @@ -952,6 +954,7 @@ static Object doString(Node inliningTarget, Object compiledRegex, Object compile pos = end; mustAdvance = start == end; } + LoopNode.reportLoopCount(inliningTarget, createTuples ? (int) Math.min(Integer.MAX_VALUE, (long) result.size() * groupCount) : result.size()); return PFactory.createList(PythonLanguage.get(inliningTarget), result.toObjectArray()); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java index c6a4a0f5d5..9c364dd814 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/SREModuleBuiltins.java @@ -74,6 +74,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; @@ -220,6 +221,7 @@ PTemplate template(VirtualFrame frame, PPattern pattern, PList template, literals[i / 2] = item; } } + LoopNode.reportLoopCount(inliningTarget, length); PythonBuiltinClassType cls = PythonBuiltinClassType.SRETemplate; Shape shape = cls.getInstanceShape(language); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java index 55dc6d940a..8fd8860451 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/zlib/ZLibModuleBuiltins.java @@ -353,14 +353,15 @@ static long doJavaBytes(PBytesLike data, int value, @Shared("b") @Cached SequenceStorageNodes.GetInternalBytesNode toBytes) { byte[] bytes = toBytes.execute(inliningTarget, data); int len = data.getSequenceStorage().length(); - return crc32(value, bytes, 0, len); + return crc32(inliningTarget, value, bytes, 0, len); } @Specialization(guards = {"!useNative()", "!isBytes(data)"}) static long doJavaObject(VirtualFrame frame, Object data, int value, + @Bind Node inliningTarget, @Shared("bb") @Cached ToBytesNode toBytesNode) { byte[] bytes = toBytesNode.execute(frame, data); - return crc32(value, bytes, 0, bytes.length); + return crc32(inliningTarget, value, bytes, 0, bytes.length); } @Fallback diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java index 0c35fc57a1..ecafd8f465 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java @@ -175,6 +175,7 @@ import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.Shape; @@ -1162,7 +1163,10 @@ static boolean access(Object object, TruffleString attrKeyName, int type, Object attr = PNone.NO_VALUE; Object klass = getClassNode.execute(inliningTarget, object); - for (PythonAbstractClass c : getMroNode.execute(inliningTarget, klass)) { + PythonAbstractClass[] mro = getMroNode.execute(inliningTarget, klass); + int i = 0; + for (; i < mro.length; i++) { + PythonAbstractClass c = mro[i]; // n.b. we need to use a different node because it makes a difference if the // type is native attr = readTypeAttrNode.execute(c, attrKeyName); @@ -1171,6 +1175,7 @@ static boolean access(Object object, TruffleString attrKeyName, int type, break; } } + LoopNode.reportLoopCount(inliningTarget, i); if (attr == PNone.NO_VALUE) { attr = readObjectAttrNode.execute(owner, attrKeyName); } @@ -1337,6 +1342,7 @@ static Object doExecute(Object receiver, Object[] arguments, for (int i = 0; loopProfile.inject(inliningTarget, i < length); i++) { starArgs[i] = iLibIterator.getIteratorNextElement(iterator); } + LoopNode.reportLoopCount(inliningTarget, starArgs.length); if (isIndexNotZeroProfile.profile(inliningTarget, index > 0)) { newArgs = new Object[index + starArgs.length]; PythonUtils.arraycopy(arguments, 0, newArgs, 0, index); @@ -1388,12 +1394,13 @@ static Object[] cached(Object[] arguments, } @Specialization(replaces = "cached") - static Object[] generic(Object[] arguments, + static Object[] generic(Node inliningTarget, Object[] arguments, @Shared @Cached(inline = false) PForeignToPTypeNode fromForeign) { Object[] convertedArgs = new Object[arguments.length]; for (int i = 0; i < arguments.length; i++) { convertedArgs[i] = fromForeign.executeConvert(arguments[i]); } + LoopNode.reportLoopCount(inliningTarget, arguments.length); return convertedArgs; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java index 049cebe02b..977d5b6d08 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/array/ArrayBuiltins.java @@ -138,6 +138,7 @@ import com.oracle.graal.python.util.BufferFormat; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.dsl.Bind; @@ -155,6 +156,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedByteValueProfile; @@ -255,6 +257,7 @@ static PArray arrayWithRangeInitializer(Node inliningTarget, Object cls, Truffle for (int index = 0, value = start; index < len; index++, value += step) { putValueNode.execute(null, inliningTarget, array, index, value); } + LoopNode.reportLoopCount(inliningTarget, len); return array; } @@ -298,6 +301,7 @@ static PArray arrayArrayInitializer(VirtualFrame frame, Node inliningTarget, Obj for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, array, i, getValueNode.execute(inliningTarget, initializer, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return array; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -319,6 +323,7 @@ static PArray arraySequenceInitializer(VirtualFrame frame, Node inliningTarget, for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, array, i, getItemNode.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return array; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -355,6 +360,7 @@ static PArray arrayIteratorInitializer(VirtualFrame frame, Node inliningTarget, break; } } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, array, length); return array; @@ -436,6 +442,7 @@ static PArray concat(PArray self, int valueIn, for (int i = 0; loopProfile.inject(inliningTarget, i < value); i++) { bufferLib.readIntoBuffer(self.getBuffer(), 0, newArray.getBuffer(), segmentLength * i, segmentLength, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, value); return newArray; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -470,6 +477,7 @@ static Object concat(PArray self, int value, for (int i = 0; i < value; i++) { bufferLib.readIntoBuffer(self.getBuffer(), 0, self.getBuffer(), segmentLength * i, segmentLength, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, value > 0 ? value : 0); return self; } catch (OverflowException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -499,17 +507,22 @@ static Object cmpItems(VirtualFrame frame, PArray left, PArray right, RichCmpOp fullCmpProfile.enter(inliningTarget); int commonLength = Math.min(left.getLength(), right.getLength()); loopProfile.profileCounted(inliningTarget, commonLength); // ignoring the early exit - for (int i = 0; loopProfile.inject(inliningTarget, i < commonLength); i++) { - Object leftValue = getLeft.execute(inliningTarget, left, i); - Object rightValue = getRight.execute(inliningTarget, right, i); - if (!richCmpEqNode.execute(frame, inliningTarget, leftValue, rightValue, RichCmpOp.Py_EQ)) { - if (op == RichCmpOp.Py_EQ) { - return false; - } else if (op == RichCmpOp.Py_NE) { - return true; + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < commonLength); i++) { + Object leftValue = getLeft.execute(inliningTarget, left, i); + Object rightValue = getRight.execute(inliningTarget, right, i); + if (!richCmpEqNode.execute(frame, inliningTarget, leftValue, rightValue, RichCmpOp.Py_EQ)) { + if (op == RichCmpOp.Py_EQ) { + return false; + } else if (op == RichCmpOp.Py_NE) { + return true; + } + return richCmpOpNode.execute(frame, inliningTarget, leftValue, rightValue, op); } - return richCmpOpNode.execute(frame, inliningTarget, leftValue, rightValue, op); } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (op.isEqOrNe()) { return op.isEq(); @@ -539,12 +552,17 @@ static boolean cmpDoubles(VirtualFrame frame, PArray left, PArray right, RichCmp fullCmpProfile.enter(inliningTarget); int commonLength = Math.min(left.getLength(), right.getLength()); loopProfile.profileCounted(inliningTarget, commonLength); // ignoring the early exit - for (int i = 0; loopProfile.inject(inliningTarget, i < commonLength); i++) { - double leftValue = (Double) getLeft.execute(inliningTarget, left, i); - double rightValue = (Double) getRight.execute(inliningTarget, right, i); - if (leftValue != rightValue) { - return op.compare(leftValue, rightValue); + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < commonLength); i++) { + double leftValue = (Double) getLeft.execute(inliningTarget, left, i); + double rightValue = (Double) getRight.execute(inliningTarget, right, i); + if (leftValue != rightValue) { + return op.compare(leftValue, rightValue); + } } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (op.isEqOrNe()) { return op.isEq(); @@ -618,6 +636,7 @@ static TruffleString repr(VirtualFrame frame, PArray self, Object value = getValueNode.execute(inliningTarget, self, i); appendStringNode.execute(sb, cast.execute(inliningTarget, repr.execute(frame, inliningTarget, value))); } + LoopNode.reportLoopCount(inliningTarget, length); appendStringNode.execute(sb, T_RBRACKET); } } @@ -690,6 +709,7 @@ static Object doSlice(PArray self, PSlice slice, for (int i = sliceInfo.start, j = 0; j < sliceInfo.sliceLength; i += sliceInfo.step, j++) { bufferLib.readIntoBuffer(self.getBuffer(), i << itemShift, newArray.getBuffer(), j << itemShift, itemsize, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, sliceInfo.sliceLength); } return newArray; } @@ -835,6 +855,7 @@ static void setitem(PArray self, PSlice slice, Object other, for (cur = start, offset = 0; offset < sliceLength - 1; cur += step, offset++) { bufferLib.readIntoBuffer(self.getBuffer(), (cur + 1) << itemShift, self.getBuffer(), (cur - offset) << itemShift, (step - 1) << itemShift, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, offset); bufferLib.readIntoBuffer(self.getBuffer(), (cur + 1) << itemShift, self.getBuffer(), (cur - offset) << itemShift, (length - cur - 1) << itemShift, bufferLib); setLengthNode.execute(inliningTarget, self, length - sliceLength); } @@ -843,6 +864,7 @@ static void setitem(PArray self, PSlice slice, Object other, for (int cur = start, i = 0; i < sliceLength; cur += step, i++) { bufferLib.readIntoBuffer(sourceBuffer, i << itemShift, self.getBuffer(), cur << itemShift, itemsize, bufferLib); } + LoopNode.reportLoopCount(inliningTarget, sliceLength); } else { wrongLengthProfile.enter(inliningTarget); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ATTEMPT_ASSIGN_ARRAY_OF_SIZE, needed, sliceLength); @@ -1078,6 +1100,7 @@ static Object extend(VirtualFrame frame, PArray self, PSequence value, putValueNode.execute(frame, inliningTarget, self, length, getItemNode.execute(inliningTarget, storage, i)); setLengthNode.execute(inliningTarget, self, ++length); } + LoopNode.reportLoopCount(inliningTarget, storageLength); return PNone.NONE; } @@ -1113,7 +1136,6 @@ static Object extend(VirtualFrame frame, PArray self, Object value, putValueNode.execute(frame, inliningTarget, self, length - 1, nextValue); setLengthNode.execute(inliningTarget, self, length); } - return PNone.NONE; } @@ -1175,6 +1197,7 @@ static Object remove(VirtualFrame frame, PArray self, Object value, if (eqNode.execute(frame, inliningTarget, item, value, RichCmpOp.Py_EQ)) { self.checkCanResize(inliningTarget, raiseNode); deleteSliceNode.execute(inliningTarget, self, i, 1); + LoopNode.reportLoopCount(inliningTarget, i + 1); return PNone.NONE; } } @@ -1313,6 +1336,7 @@ static Object fromlist(VirtualFrame frame, PArray self, PList list, for (int i = 0; i < length; i++) { putValueNode.execute(frame, inliningTarget, self, self.getLength() + i, getItemScalarNode.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, self, newLength); return PNone.NONE; } catch (OverflowException e) { @@ -1358,6 +1382,7 @@ static Object fromunicode(VirtualFrame frame, PArray self, TruffleString str, TruffleString value = fromCodePointNode.execute(nextNode.execute(it, TS_ENCODING), TS_ENCODING, true); putValueNode.execute(frame, inliningTarget, self, self.getLength() + codePointIndex++, value); } + LoopNode.reportLoopCount(inliningTarget, length); setLengthNode.execute(inliningTarget, self, newLength); return PNone.NONE; } catch (OverflowException e) { @@ -1421,6 +1446,7 @@ static TruffleString tounicode(PArray self, for (int i = 0; i < length; i++) { appendStringNode.execute(sb, (TruffleString) getValueNode.execute(inliningTarget, self, i)); } + LoopNode.reportLoopCount(inliningTarget, length); return toStringNode.execute(sb); } } @@ -1463,6 +1489,8 @@ static Object tofile(VirtualFrame frame, PArray self, Object file, callMethod.execute(frame, inliningTarget, file, T_WRITE, PFactory.createBytes(language, buffer)); remaining -= blocksize; } + // Rounding up remaining to whole blocks above can overflow to a negative nblocks. + LoopNode.reportLoopCount(inliningTarget, Math.max(0, nblocks)); } return PNone.NONE; } @@ -1479,29 +1507,35 @@ static Object byteswap1(@SuppressWarnings("unused") PArray self) { @Specialization(guards = "self.getFormat().bytesize == 2") static Object byteswap2(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 2, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 2, self.getBuffer(), bufferLib); return PNone.NONE; } @Specialization(guards = "self.getFormat().bytesize == 4") static Object byteswap4(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 4, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 4, self.getBuffer(), bufferLib); return PNone.NONE; } @Specialization(guards = "self.getFormat().bytesize == 8") static Object byteswap8(PArray self, + @Bind Node inliningTarget, @Shared @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib) { - doByteSwapExploded(self, 8, self.getBuffer(), bufferLib); + doByteSwapExploded(inliningTarget, self, 8, self.getBuffer(), bufferLib); return PNone.NONE; } - private static void doByteSwapExploded(PArray self, int itemsize, Object buffer, PythonBufferAccessLibrary bufferLib) { + private static void doByteSwapExploded(Node inliningTarget, PArray self, int itemsize, Object buffer, PythonBufferAccessLibrary bufferLib) { + CompilerAsserts.compilationConstant(itemsize); for (int i = 0; i < self.getBytesLength(); i += itemsize) { doByteSwapExplodedInnerLoop(buffer, itemsize, i, bufferLib); } + // over-reporting, but also inner loop is not counted... + LoopNode.reportLoopCount(inliningTarget, self.getBytesLength()); } @ExplodeLoop @@ -1537,9 +1571,11 @@ static int index(VirtualFrame frame, PArray self, Object value, int start, int s } for (int i = start; i < stop && i < length; i++) { if (eqNode.execute(frame, inliningTarget, getValueNode.execute(inliningTarget, self, i), value, RichCmpOp.Py_EQ)) { + LoopNode.reportLoopCount(inliningTarget, i - start + 1); return i; } } + LoopNode.reportLoopCount(inliningTarget, Math.min(stop, length) > start ? Math.min(stop, length) - start : 0); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ARRAY_INDEX_X_NOT_IN_ARRAY); } @@ -1573,6 +1609,7 @@ abstract static class ReverseNode extends PythonUnaryBuiltinNode { @Specialization static Object reverse(PArray self, + @Bind Node inliningTarget, @CachedLibrary(limit = "2") PythonBufferAccessLibrary bufferLib) { int itemsize = self.getFormat().bytesize; int itemShift = self.getItemSizeShift(); @@ -1583,6 +1620,7 @@ static Object reverse(PArray self, bufferLib.readIntoBuffer(self.getBuffer(), (length - i - 1) << itemShift, self.getBuffer(), i << itemShift, itemsize, bufferLib); bufferLib.writeFromByteArray(self.getBuffer(), (length - i - 1) << itemShift, tmp, 0, itemsize); } + LoopNode.reportLoopCount(inliningTarget, length / 2); return PNone.NONE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java index 749e361a53..c03e05b545 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/asyncio/AsyncGenThrowBuiltins.java @@ -1,5 +1,5 @@ /* - * 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 @@ -41,7 +41,7 @@ package com.oracle.graal.python.builtins.objects.asyncio; import static com.oracle.graal.python.builtins.objects.asyncio.PAsyncGenASend.AwaitableState; -import static com.oracle.graal.python.nodes.ErrorMessages.GENERATOR_IGNORED_EXIT; +import static com.oracle.graal.python.nodes.ErrorMessages.ASYNCGEN_IGNORED_EXIT; import static com.oracle.graal.python.nodes.ErrorMessages.SEND_NON_NONE_TO_UNSTARTED_GENERATOR; import java.util.List; @@ -174,6 +174,7 @@ public Object send(VirtualFrame frame, PAsyncGenAThrow self, Object sent, if (isAGWrappedValue.profileObject(inliningTarget, retval, PythonBuiltinClassType.PAsyncGenAWrappedValue)) { throw yieldClose(inliningTarget, self, gen); } + return retval; } else { // athrow mode try { @@ -212,7 +213,7 @@ public Object send(VirtualFrame frame, PAsyncGenAThrow self, Object sent, static PException yieldClose(Node inliningTarget, PAsyncGenAThrow athrow, PAsyncGen gen) { gen.setRunningAsync(false); athrow.setState(AwaitableState.CLOSED); - return PRaiseNode.raiseStatic(inliningTarget, PythonBuiltinClassType.RuntimeError, GENERATOR_IGNORED_EXIT); + return PRaiseNode.raiseStatic(inliningTarget, PythonBuiltinClassType.RuntimeError, ASYNCGEN_IGNORED_EXIT); } static PException checkError(PAsyncGenAThrow athrow, PAsyncGen gen, PException exception, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java index 0c31775649..ba8768cbf5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/ForeignBufferAcquireExports.java @@ -59,6 +59,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -176,6 +177,7 @@ void readIntoBuffer(int srcOffset, Object dest, int destOffset, int length, Pyth for (int i = 0; i < length; i++) { otherLib.writeByte(dest, destOffset + i, readByte(srcOffset + i, interop)); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, length)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java index d74ab10fe0..4ecfe395e3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/buffer/PythonBufferAccessLibrary.java @@ -51,6 +51,7 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.GenerateLibrary; @@ -198,6 +199,7 @@ public void readIntoByteArray(Object receiver, int srcOffset, byte[] dest, int d for (int i = 0; i < length; i++) { dest[destOffset + i] = readByte(receiver, srcOffset + i); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } @@ -218,6 +220,7 @@ public void writeFromByteArray(Object receiver, int destOffset, byte[] src, int for (int i = 0; i < length; i++) { writeByte(receiver, destOffset + i, src[srcOffset + i]); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } @@ -239,6 +242,7 @@ public void readIntoBuffer(Object receiver, int srcOffset, Object dest, int dest for (int i = 0; i < length; i++) { otherLib.writeByte(dest, destOffset + i, readByte(receiver, srcOffset + i)); } + LoopNode.reportLoopCount(this, Math.max(0, length)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java index 44bed66f34..794ef94f73 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/ByteArrayBuiltins.java @@ -760,11 +760,11 @@ static PByteArray translate(VirtualFrame frame, PByteArray self, Object table, O Result result; if (bTable != null && bDelete != null) { - result = translateAndDelete(bSelf, bTable, bDelete); + result = translateAndDelete(inliningTarget, bSelf, bTable, bDelete); } else if (bTable != null) { result = translate(bSelf, bTable); } else if (bDelete != null) { - result = delete(bSelf, bDelete); + result = delete(inliningTarget, bSelf, bDelete); } else { return PFactory.createByteArray(language, bSelf); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java index 45e196dc27..60f3a9bf04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesBuiltins.java @@ -330,11 +330,11 @@ static Object translate(VirtualFrame frame, Object self, Object table, Object de Result result; if (bTable != null && bDelete != null) { - result = translateAndDelete(bSelf, bTable, bDelete); + result = translateAndDelete(inliningTarget, bSelf, bTable, bDelete); } else if (bTable != null) { result = translate(bSelf, bTable); } else if (bDelete != null) { - result = delete(bSelf, bDelete); + result = delete(inliningTarget, bSelf, bDelete); } else if (!checkExactNode.execute(inliningTarget, self)) { return PFactory.createBytes(language, bSelf); } else { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java index 558e063b3d..5920ee72a9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java @@ -424,9 +424,11 @@ private boolean doIt(VirtualFrame frame, byte[] self, int len, SequenceStorage s Object element = getItemNode.execute(inliningTarget, substrsStorage, i); byte[] bytes = tobytes.execute(frame, element); if (doIt(self, len, bytes, start, stop)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, substrsStorage.length()); return false; } } @@ -886,9 +888,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (b[i] < 0) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -919,9 +923,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isAlnum(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -952,9 +958,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isAlpha(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -985,9 +993,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isDigit(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -1023,10 +1033,12 @@ static boolean check(Object buffer, if (!BytesUtils.isUpper(ch)) { uncased++; } else { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } } + LoopNode.reportLoopCount(inliningTarget, len); return uncased == 0 || len > uncased; } finally { bufferLib.release(buffer); @@ -1062,10 +1074,12 @@ static boolean check(Object buffer, if (!BytesUtils.isLower(ch)) { uncased++; } else { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } } + LoopNode.reportLoopCount(inliningTarget, len); return uncased == 0 || len > uncased; } finally { bufferLib.release(buffer); @@ -1096,9 +1110,11 @@ static boolean check(Object buffer, byte[] b = bufferLib.getInternalOrCopiedByteArray(buffer); for (int i = 0; i < len; i++) { if (!BytesUtils.isSpace(b[i])) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } + LoopNode.reportLoopCount(inliningTarget, len); return true; } finally { bufferLib.release(buffer); @@ -1134,18 +1150,21 @@ static boolean check(Object buffer, if (BytesUtils.isUpper(ch)) { if (previousIsCased) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } previousIsCased = true; cased = true; } else if (BytesUtils.isLower(ch)) { if (!previousIsCased) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } else { previousIsCased = false; } } + LoopNode.reportLoopCount(inliningTarget, len); return cased; } finally { bufferLib.release(buffer); @@ -1273,6 +1292,7 @@ protected byte[] make(byte[] self, int len, int width, byte fill) { for (int i = l, j = 0; i < (len + l); j++, i++) { res[i] = self[j]; } + LoopNode.reportLoopCount(this, len); return res; } @@ -1400,6 +1420,7 @@ static PBytesLike replace(Object self, for (int i = 0; i < bytes.length; ++i) { bytes[i] = toLower(bytes[i]); } + LoopNode.reportLoopCount(node, bytes.length); return create.execute(node, self, bytes); } } @@ -1417,6 +1438,7 @@ static PBytesLike replace(Object self, for (int i = 0; i < bytes.length; ++i) { bytes[i] = toUpper(bytes[i]); } + LoopNode.reportLoopCount(inliningTarget, bytes.length); return create.execute(inliningTarget, self, bytes); } } @@ -1679,6 +1701,8 @@ protected ArrayBuilder splitSingle(byte[] bytes, int len, byte sep, int } } } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); + LoopNode.reportLoopCount(this, j); if (i <= len) { list.add(copyOfRange(bytes, i, len)); } @@ -1701,6 +1725,7 @@ protected ArrayBuilder splitDelimiter(byte[] bytes, int len, byte[] sep, list.add(copyOfRange(bytes, i, j)); i = j + sepLen; } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); list.add(copyOfRange(bytes, i, len)); @@ -1743,6 +1768,7 @@ protected ArrayBuilder splitWhitespace(byte[] bytes, int len, int maxspl } list.add(copyOfRange(bytes, i + 1, j + 1)); } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); if (i >= 0) { /* Only occurs when maxcount was reached */ @@ -1754,6 +1780,7 @@ protected ArrayBuilder splitWhitespace(byte[] bytes, int len, int maxspl list.add(copyOfRange(bytes, 0, i + 1)); } } + LoopNode.reportLoopCount(this, len - 1 - i); list.reverse(); return list; } @@ -1773,6 +1800,8 @@ protected ArrayBuilder splitSingle(byte[] bytes, int len, byte sep, int } } } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); + LoopNode.reportLoopCount(this, len - (i + 1)); if (j >= -1) { list.add(copyOfRange(bytes, 0, j + 1)); } @@ -1798,6 +1827,7 @@ protected ArrayBuilder splitDelimiter(byte[] bytes, int len, byte[] sep, list.add(copyOfRange(bytes, pos + sepLen, j)); j = pos; } + LoopNode.reportLoopCount(this, maxsplit - Math.max(0, maxcount)); list.add(copyOfRange(bytes, 0, j)); list.reverse(); return list; @@ -2036,6 +2066,7 @@ static PBytes maketrans(VirtualFrame frame, @SuppressWarnings("unused") Object c byte value = fromB[i]; table[value < 0 ? value + 256 : value] = toB[i]; } + LoopNode.reportLoopCount(inliningTarget, fromB.length); return PFactory.createBytes(language, table); } @@ -2059,6 +2090,7 @@ static PBytesLike capitalize(Object self, for (int i = 1; i < b.length; i++) { b[i] = toLower(b[i]); } + LoopNode.reportLoopCount(inliningTarget, b.length - 1); return create.execute(inliningTarget, self, b); } } @@ -2095,6 +2127,7 @@ static PBytesLike title(Object self, } b[i] = c; } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, b); } @@ -2120,6 +2153,7 @@ static PBytesLike swapcase(Object self, b[i] = toUpper(b[i]); } } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, b); } } @@ -2173,6 +2207,7 @@ static PBytesLike expandtabs(Object self, int tabsize, } } } + LoopNode.reportLoopCount(inliningTarget, len); if (i > max - j) { throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.RESULT_TOO_LONG); } @@ -2198,6 +2233,7 @@ static PBytesLike expandtabs(Object self, int tabsize, } } + LoopNode.reportLoopCount(inliningTarget, b.length); return create.execute(inliningTarget, self, q); } @@ -2219,16 +2255,16 @@ static PBytesLike zfill(Object self, int width, @Cached GetInternalByteArrayNode getInternalByteArrayNode, @Cached BytesNodes.CreateBytesNode create) { SequenceStorage storage = getBytesStorage.execute(inliningTarget, self); - return create.execute(inliningTarget, self, zfill(getInternalByteArrayNode.execute(inliningTarget, storage), storage.length(), width)); + return create.execute(inliningTarget, self, zfill(inliningTarget, getInternalByteArrayNode.execute(inliningTarget, storage), storage.length(), width)); } - private static byte[] zfill(byte[] self, int len, int width) { + private static byte[] zfill(Node inliningTarget, byte[] self, int len, int width) { if (len >= width) { return self; } int fill = width - len; - byte[] p = pad(self, len, fill, 0, (byte) '0'); + byte[] p = pad(inliningTarget, self, len, fill, 0, (byte) '0'); if (len == 0) { return p; @@ -2242,7 +2278,7 @@ private static byte[] zfill(byte[] self, int len, int width) { return p; } - private static byte[] pad(byte[] self, int len, int l, int r, byte fillChar) { + private static byte[] pad(Node inliningTarget, byte[] self, int len, int l, int r, byte fillChar) { int left = (l < 0) ? 0 : l; int right = (r < 0) ? 0 : r; if (left == 0 && right == 0) { @@ -2256,6 +2292,7 @@ private static byte[] pad(byte[] self, int len, int l, int r, byte fillChar) { for (int i = left, j = 0; i < (left + len); j++, i++) { u[i] = self[j]; } + LoopNode.reportLoopCount(inliningTarget, len); if (right > 0) { Arrays.fill(u, left + len, u.length, fillChar); } @@ -2311,12 +2348,14 @@ static PBytesLike remove(VirtualFrame frame, Object self, Object prefix, for (int i = 0; i < selfBsLen; i++) { if (i < prefixBsLen) { if (selfBs[i] != prefixBs[i]) { + LoopNode.reportLoopCount(node, i); return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); } } else { result[j++] = selfBs[i]; } } + LoopNode.reportLoopCount(node, selfBsLen); return create.execute(node, self, result); } return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); @@ -2352,12 +2391,14 @@ static PBytesLike remove(VirtualFrame frame, Object self, Object suffix, for (int i = selfBsLen - 1, j = 1; i >= 0; i--, j++) { if (i >= selfBsLen - suffixBsLen) { if (selfBs[i] != suffixBs[suffixBsLen - j]) { + LoopNode.reportLoopCount(node, selfBsLen - i - 1); return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); } } else { result[result.length - k++] = selfBs[i]; } } + LoopNode.reportLoopCount(node, selfBsLen); return create.execute(node, self, result); } return create.execute(node, self, PythonUtils.arrayCopyOf(selfBs, selfBsLen)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java index 4b8b7233bf..e9b7eae418 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesNodes.java @@ -124,6 +124,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.InternalByteArray; @@ -194,6 +195,7 @@ static byte[] join(VirtualFrame frame, Node inliningTarget, byte[] sep, Object i try { next = nextNode.execute(frame, inliningTarget, iterator); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, parts.size()); return joinArrays(sep, parts, partsTotalSize); } partsTotalSize += append(parts, toBytesNode.execute(frame, next)); @@ -706,7 +708,7 @@ public abstract static class ByteToHexNode extends PNodeWithContext { public abstract TruffleString execute(Node inliningTarget, byte[] argbuf, int arglen, byte sep, int bytesPerSepGroup); @Specialization(guards = "bytesPerSepGroup == 0") - static TruffleString zero(byte[] argbuf, int arglen, @SuppressWarnings("unused") byte sep, @SuppressWarnings("unused") int bytesPerSepGroup, + static TruffleString zero(Node inliningTarget, byte[] argbuf, int arglen, @SuppressWarnings("unused") byte sep, @SuppressWarnings("unused") int bytesPerSepGroup, @Shared @Cached TruffleString.FromByteArrayWithCompactionUTF32Node fromByteArrayNode) { int resultlen = arglen * 2; @@ -718,6 +720,7 @@ static TruffleString zero(byte[] argbuf, int arglen, @SuppressWarnings("unused") retbuf[j++] = BytesUtils.HEXDIGITS[c >>> 4]; retbuf[j++] = BytesUtils.HEXDIGITS[c & 0x0f]; } + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } @@ -739,7 +742,7 @@ static TruffleString negative(Node inliningTarget, byte[] argbuf, int arglen, by resultlen += arglen * 2; if (absBytesPerSepGroup >= arglen) { - return zero(argbuf, arglen, sep, 0, fromByteArrayNode); + return zero(inliningTarget, argbuf, arglen, sep, 0, fromByteArrayNode); } byte[] retbuf = new byte[resultlen]; @@ -758,7 +761,7 @@ static TruffleString negative(Node inliningTarget, byte[] argbuf, int arglen, by retbuf[j++] = BytesUtils.HEXDIGITS[c >>> 4]; retbuf[j++] = BytesUtils.HEXDIGITS[c & 0x0f]; } - + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } @@ -780,7 +783,7 @@ static TruffleString positive(Node inliningTarget, byte[] argbuf, int arglen, by resultlen += arglen * 2; if (absBytesPerSepGroup >= arglen) { - return zero(argbuf, arglen, sep, 0, fromByteArrayNode); + return zero(inliningTarget, argbuf, arglen, sep, 0, fromByteArrayNode); } byte[] retbuf = new byte[resultlen]; @@ -800,6 +803,7 @@ static TruffleString positive(Node inliningTarget, byte[] argbuf, int arglen, by retbuf[j--] = BytesUtils.HEXDIGITS[c & 0x0f]; retbuf[j--] = BytesUtils.HEXDIGITS[c >>> 4]; } + LoopNode.reportLoopCount(inliningTarget, arglen); return fromByteArrayNode.execute(retbuf, 0, retbuf.length, TruffleString.CompactionLevel.S1, false); } } @@ -1075,24 +1079,26 @@ protected static boolean[] createDeleteTable(byte[] delete) { for (int i = 0; i < 256; i++) { result[i] = false; } - for (byte b : delete) { - result[b & 0xFF] = true; + for (int i = 0; i < delete.length; i++) { + result[delete[i] & 0xFF] = true; } return result; } - protected static Result delete(byte[] self, byte[] table) { + protected static Result delete(Node inliningTarget, byte[] self, byte[] table) { final int length = self.length; byte[] result = new byte[length]; int resultLen = 0; boolean[] toDelete = createDeleteTable(table); - for (byte b : self) { + for (int i = 0; i < length; i++) { + byte b = self[i]; if (!toDelete[b & 0xFF]) { result[resultLen] = b; resultLen++; } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) length + table.length)); if (resultLen == length) { return new Result(result, false); } @@ -1114,14 +1120,15 @@ protected static Result translate(byte[] self, byte[] table) { return new Result(result, changed); } - protected static Result translateAndDelete(byte[] self, byte[] table, byte[] delete) { + protected static Result translateAndDelete(Node inliningTarget, byte[] self, byte[] table, byte[] delete) { final int length = self.length; byte[] result = new byte[length]; int resultLen = 0; boolean changed = false; boolean[] toDelete = createDeleteTable(delete); - for (byte value : self) { + for (int i = 0; i < length; i++) { + byte value = self[i]; int idx = value & 0xFF; if (!toDelete[idx]) { byte b = table[idx]; @@ -1132,6 +1139,7 @@ protected static Result translateAndDelete(byte[] self, byte[] table, byte[] del resultLen++; } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) length + delete.length)); if (resultLen == length) { return new Result(result, changed); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java index ed6689f364..ef7f80fa81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java @@ -1226,7 +1226,7 @@ public static Object loadCExtModule(Node location, PythonContext context, Module CApiContext cApiContext = CApiContext.ensureCapiWasLoaded(location, context, spec.name, spec.path); NativeLibrary library; - TruffleFile realPath = context.getPublicTruffleFileRelaxed(spec.path, context.getExtensionSuffix()).getCanonicalFile(); + TruffleFile realPath = context.getPublicTruffleFileRelaxed(spec.path.toJavaStringUncached(), context.getExtensionSuffix().toJavaStringUncached()).getCanonicalFile(); String loadPath = cApiContext.nativeLibraryLocator.resolve(context, realPath); getLogger(CApiContext.class).config(String.format("loading module %s (real path: %s) as native", spec.path, loadPath)); int dlopenFlags = context.getDlopenFlags(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 94a8219899..f3f18b0b54 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -189,6 +189,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -1248,7 +1249,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } kwnamesTuplePtr = createNativeKwNamesTupleNode.execute(context, fastcallKwnames); } - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(fastcallArgs, argToNativeNode); + LoopNode.reportLoopCount(this, fastcallArgs.length); + long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCFUNCTION_FAST_WITH_KEYWORDS(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1330,7 +1332,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati } kwnamesTuple = PFactory.createTuple(context.getLanguage(), fastcallKwnames); } - long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(fastcallArgs, argToNativeNode); + LoopNode.reportLoopCount(this, fastcallArgs.length); + long nativeFastcallArgs = MethFastcallRoot.createFastcallArgsArray(this, fastcallArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCMETHOD(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1394,7 +1397,8 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati for (int i = 0; i < args.length; i++) { promotedArgs[i] = ensurePythonObject(args[i]); } - long argsArray = createFastcallArgsArray(promotedArgs, argToNativeNode); + LoopNode.reportLoopCount(this, args.length); + long argsArray = createFastcallArgsArray(this, promotedArgs, argToNativeNode); try { long l = ExternalFunctionInvoker.invokePYCFUNCTION_FAST(frame, timing, context.ensureNativeContext(), boundaryCallData, ensureGetThreadStateNode().executeCached(context), @@ -1412,7 +1416,7 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati * {@code PyObject *arr[]}. This will not create new {@code PyObject *} references (i.e. * refcount is not increased). */ - static long createFastcallArgsArray(Object[] data, PythonToNativeNode argToNativeNode) { + static long createFastcallArgsArray(Node inliningTarget, Object[] data, PythonToNativeNode argToNativeNode) { if (data.length == 0) { return NULLPTR; } @@ -1422,6 +1426,7 @@ static long createFastcallArgsArray(Object[] data, PythonToNativeNode argToNativ assert EnsurePythonObjectNode.doesNotNeedPromotion(data[i]); NativeMemory.writePtrArrayElement(ptr, i, argToNativeNode.execute(data[i])); } + LoopNode.reportLoopCount(inliningTarget, data.length); return ptr; } @@ -2369,6 +2374,7 @@ static long doGeneric(PythonContext context, Object[] args, * instances. */ @GenerateInline(false) + @GenerateUncached public abstract static class CreateNativeKwNamesTupleNode extends Node { public abstract long execute(PythonContext context, Object[] args); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java index 53d9624e82..25fa86bf80 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java @@ -254,7 +254,9 @@ public enum ExternalFunctionSignature implements NativeCExtSymbol { // TODO(fa): should be an implicit signature GCCOLLECT(false, Py_ssize_t, Int), - GETDICTPTRFUN(true, Pointer, PyObject); + GETDICTPTRFUN(true, Pointer, PyObject), + // typedef PyObject *(*vectorcallfunc)(PyObject *, PyObject *const *, size_t, PyObject *); + VECTORCALL(false, PyObjectReturn, PyObject, Pointer, Py_ssize_t, PyObject); public final ArgDescriptor returnValue; public final ArgDescriptor[] arguments; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java index afe09b08f6..00c10dc088 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java @@ -153,6 +153,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -1908,11 +1909,13 @@ static long doNative(Node inliningTarget, PythonAbstractNativeObject obj, boolea if (PythonLanguage.get(inliningTarget).getEngineOption(PythonOptions.PythonGC) && newRefcnt == MANAGED_REFCNT + 1 && obj.getReplicatedNativeReferences() != null) { hasReplicatedNativeReferences.enter(inliningTarget); - for (Object referent : obj.getReplicatedNativeReferences()) { - if (referent instanceof PythonObject pythonObject) { + Object[] referents = obj.getReplicatedNativeReferences(); + for (int i = 0; i < referents.length; i++) { + if (referents[i] instanceof PythonObject pythonObject) { updateRefNode.execute(inliningTarget, pythonObject, pythonObject.getRefCount()); } } + LoopNode.reportLoopCount(inliningTarget, referents.length); } } return obj.getPtr(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java index 608299765d..43ade28b81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/DynamicObjectStorage.java @@ -71,6 +71,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; import com.oracle.truffle.api.nodes.Node; @@ -174,6 +175,7 @@ static int cachedLen(DynamicObjectStorage self, @Specialization(guards = {"self.cachedLength < 0", "!hasNoDeletedProperties(self)"}, replaces = "cachedLen") static int length(DynamicObjectStorage self, + @Bind Node inliningTarget, @Shared @Cached(inline = false) ReadAttributeFromPythonObjectNode readNode, @Cached DynamicObject.GetKeyArrayNode keyArrayNode) { Object[] keys = keyArrayNode.execute(self.store); @@ -181,6 +183,7 @@ static int length(DynamicObjectStorage self, for (Object key : keys) { len = incrementLen(self, readNode, len, key); } + LoopNode.reportLoopCount(inliningTarget, keys.length); return cacheLength(self, len); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java index 4eaa77eb6c..6a4992c0da 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingStorageNodes.java @@ -285,7 +285,8 @@ static EconomicMapStorage dynamicObjectStorageToEconomicMap(Node inliningTarget, Object[] keys = getKeyArrayNode.execute(store); EconomicMapStorage result = EconomicMapStorage.create(keys.length); ObjectHashMap resultMap = result; - for (Object k : keys) { + for (int i = 0; i < keys.length; i++) { + Object k = keys[i]; if (k instanceof TruffleString) { Object v = getNode.execute(store, k, PNone.NO_VALUE); if (v != PNone.NO_VALUE) { @@ -293,6 +294,7 @@ static EconomicMapStorage dynamicObjectStorageToEconomicMap(Node inliningTarget, } } } + LoopNode.reportLoopCount(inliningTarget, keys.length); return result; } @@ -1767,6 +1769,7 @@ static HashingStorage doIt(Frame frame, Node inliningTarget, PKeyword[] keywords PKeyword keyword = keywords[i]; result = setItem.execute(frame, inliningTarget, result, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, keywords.length); return result; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java index 1d7ea75209..32f98184fa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/KeywordsStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -59,6 +59,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; import com.oracle.truffle.api.nodes.Node; @@ -147,9 +148,11 @@ static Object notString(Frame frame, Node inliningTarget, KeywordsStorage self, TruffleString currentKey = self.keywords[i].getName(); long keyHash = hashNode.execute(frame, inliningTarget, currentKey); if (keyHash == hash && eqNode.executeEq(frame, inliningTarget, key, currentKey)) { + LoopNode.reportLoopCount(inliningTarget, i); return self.keywords[i].getValue(); } } + LoopNode.reportLoopCount(inliningTarget, self.keywords.length); return null; } } @@ -158,6 +161,7 @@ void addAllTo(Node inliningTarget, HashingStorage storage, SpecializedSetStringK for (PKeyword entry : keywords) { putNode.execute(inliningTarget, storage, entry.getName(), entry.getValue()); } + LoopNode.reportLoopCount(inliningTarget, keywords.length); } public HashingStorage copy() { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java index bc65651a20..e5f6c45b92 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java @@ -683,7 +683,8 @@ protected static EmptySequenceStorage doEmpty(EmptySequenceStorage storage, int } @Specialization - protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { int[] newArray = new int[length]; int[] values = storage.getInternalIntArray(); @@ -695,12 +696,14 @@ protected static SequenceStorage doIntSequenceStorage(IntSequenceStorage storage for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new IntSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { long[] newArray = new long[length]; long[] values = storage.getInternalLongArray(); @@ -712,12 +715,14 @@ protected static SequenceStorage doLongSequenceStorage(LongSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new LongSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { double[] newArray = new double[length]; double[] values = storage.getInternalDoubleArray(); @@ -729,12 +734,14 @@ protected static SequenceStorage doDoubleSequenceStorage(DoubleSequenceStorage s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new DoubleSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { boolean[] newArray = new boolean[length]; boolean[] values = storage.getInternalBoolArray(); @@ -746,12 +753,14 @@ protected static SequenceStorage doBoolSequenceStorage(BoolSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new BoolSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { byte[] newArray = new byte[length]; byte[] values = storage.getInternalByteArray(); @@ -763,12 +772,14 @@ protected static SequenceStorage doByteSequenceStorage(ByteSequenceStorage stora for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ByteSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { Object[] newArray = new Object[length]; Object[] values = storage.getInternalObjectArray(); @@ -780,12 +791,14 @@ protected static SequenceStorage doObjectSequenceStorage(ObjectSequenceStorage s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @Specialization - protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage, int start, int stop, int step, int length) { + protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage, int start, int stop, int step, int length, + @Bind Node inliningTarget) { PythonAbstractClass[] newArray = new PythonAbstractClass[length]; PythonAbstractClass[] values = storage.getInternalClassArray(); @@ -797,6 +810,7 @@ protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @@ -804,17 +818,19 @@ protected static SequenceStorage doMroSequenceStorage(MroSequenceStorage storage @Specialization protected static SequenceStorage doNativeInt(NativeIntSequenceStorage storage, int start, int stop, int step, int length, @Bind Node node) { - NativeBuffer sliceValueBuffer = doNativePrimitiveSliceInBound(PythonContext.get(node), start, step, length, storage); + NativeBuffer sliceValueBuffer = doNativePrimitiveSliceInBound(node, PythonContext.get(node), start, step, length, storage); return PythonContext.get(node).nativeBufferContext.createNativeIntStorage(sliceValueBuffer, length); } @Specialization - protected static SequenceStorage doNativeByte(NativeByteSequenceStorage storage, int start, @SuppressWarnings("unused") int stop, int step, int length) { + protected static SequenceStorage doNativeByte(NativeByteSequenceStorage storage, int start, @SuppressWarnings("unused") int stop, int step, int length, + @Bind Node inliningTarget) { byte[] newArray = new byte[length]; for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = readByteArrayElement(storage.getPtr(), i); } + LoopNode.reportLoopCount(inliningTarget, length); return new ByteSequenceStorage(newArray); } @@ -826,6 +842,7 @@ protected static SequenceStorage doNativeObject(NativeObjectSequenceStorage stor for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = toJavaNode.execute(inliningTarget, readPtrArrayElement(storage.getPtr(), i)); } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } @@ -837,10 +854,11 @@ protected static SequenceStorage doForeign(ForeignSequenceStorage storage, int s for (int i = start, j = 0; j < length; i += step, j++) { newArray[j] = readNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, length); return new ObjectSequenceStorage(newArray); } - private static NativeBuffer doNativePrimitiveSliceInBound(PythonContext pythonCtx, int start, int step, int sliceLength, NativePrimitiveSequenceStorage storage) { + private static NativeBuffer doNativePrimitiveSliceInBound(Node inliningTarget, PythonContext pythonCtx, int start, int step, int sliceLength, NativePrimitiveSequenceStorage storage) { var unsafe = pythonCtx.getUnsafe(); long itemSize = storage.getItemSize(); long sizeInBytes = sliceLength * itemSize; @@ -857,6 +875,7 @@ private static NativeBuffer doNativePrimitiveSliceInBound(PythonContext pythonCt j = 0; j < sliceLength; srcAddr += stepInBytes, destAddr += itemSize, j++) { unsafe.copyMemory(srcAddr, destAddr, itemSize); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, sliceLength)); return sliceBuffer; } @@ -1493,6 +1512,7 @@ protected static void doOther(Node inliningTarget, SequenceStorage storage, int // otherwise copying forwards copyForward(inliningTarget, storage, getRightItemNode, setLeftItemNode, distPos, srcPos, length); } + LoopNode.reportLoopCount(inliningTarget, length); } private static void copyForward(Node inliningTarget, SequenceStorage storage, GetItemScalarNode getRightItemNode, SetItemScalarNode setLeftItemNode, int destPos, int srcPos, int length) { @@ -1551,6 +1571,7 @@ protected static void doOther(Node inliningTarget, SequenceStorage dist, int dis for (int cur = distPos, j = srcPos, i = 0; i < length; cur += 1, j++, i++) { setLeftItemNode.execute(inliningTarget, dist, cur, getRightItemNode.execute(inliningTarget, src, j)); } + LoopNode.reportLoopCount(inliningTarget, length); } protected static boolean isArrayBasedSequenceStorage(Object o) { @@ -1571,28 +1592,33 @@ static void doEmpty(@SuppressWarnings("unused") EmptySequenceStorage storage) { } @Specialization - static void doIntStorage(IntSequenceStorage storage) { + static void doIntStorage(Node inliningTarget, IntSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doDoubleStorage(DoubleSequenceStorage storage) { + static void doDoubleStorage(Node inliningTarget, DoubleSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doLongStorage(LongSequenceStorage storage) { + static void doLongStorage(Node inliningTarget, LongSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doByteStorage(ByteSequenceStorage storage) { + static void doByteStorage(Node inliningTarget, ByteSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization - static void doObjectStorage(ObjectSequenceStorage storage) { + static void doObjectStorage(Node inliningTarget, ObjectSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization @@ -1610,11 +1636,13 @@ static void doNativePrimitive(Node inliningTarget, NativePrimitiveSequenceStorag startAddress += itemSize; endAddress -= itemSize; } + LoopNode.reportLoopCount(inliningTarget, length / 2); } @Specialization - static void doBoolStorage(BoolSequenceStorage storage) { + static void doBoolStorage(Node inliningTarget, BoolSequenceStorage storage) { storage.reverse(); + LoopNode.reportLoopCount(inliningTarget, (storage.length() >>> 1) + (storage.length() & 1)); } @Specialization @@ -1645,6 +1673,7 @@ static void doForeign(Node inliningTarget, ForeignSequenceStorage storage, writeNode.execute(inliningTarget, storage, head, readNode.execute(inliningTarget, storage, tail)); writeNode.execute(inliningTarget, storage, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } @@ -1655,7 +1684,8 @@ abstract static class ReverseNativeNode extends Node { abstract void execute(NativeSequenceStorage storage); @Specialization - static void doNativeByte(NativeByteSequenceStorage storage) { + static void doNativeByte(NativeByteSequenceStorage storage, + @Bind Node inliningTarget) { int length = storage.length(); if (length > 0) { int head = 0; @@ -1668,11 +1698,13 @@ static void doNativeByte(NativeByteSequenceStorage storage) { writeByteArrayElement(ptr, head, readByteArrayElement(ptr, tail)); writeByteArrayElement(ptr, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } @Specialization - static void doNativeObject(NativeObjectSequenceStorage storage) { + static void doNativeObject(NativeObjectSequenceStorage storage, + @Bind Node inliningTarget) { int length = storage.length(); if (length > 0) { int head = 0; @@ -1685,6 +1717,7 @@ static void doNativeObject(NativeObjectSequenceStorage storage) { writePtrArrayElement(ptr, head, readPtrArrayElement(ptr, tail)); writePtrArrayElement(ptr, tail, temp); } + LoopNode.reportLoopCount(inliningTarget, (length >>> 1) + (length & 1)); } } } @@ -1763,6 +1796,7 @@ static void multiStep(SequenceStorage self, SliceInfo sinfo, SequenceStorage val for (int cur = start, i = 0; i < slicelen; cur += step, i++) { setLeftItemNode.execute(inliningTarget, self, cur, getRightItemNode.execute(inliningTarget, data, i)); } + LoopNode.reportLoopCount(inliningTarget, slicelen); } } @@ -2142,6 +2176,7 @@ static byte[] doNativeByte(Node inliningTarget, NativeByteSequenceStorage s, assert elem >= 0 && elem < 256; barr[i] = (byte) elem; } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } @@ -2167,6 +2202,7 @@ static byte[] doGeneric(Node inliningTarget, SequenceStorage s, for (int i = 0; i < barr.length; i++) { barr[i] = castToByteNode.execute(inliningTarget, getItemNode.execute(inliningTarget, s, i)); } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } } @@ -2311,6 +2347,7 @@ static SequenceStorage doGenericInplace(@SuppressWarnings("unused") SequenceStor for (int i = 0; i < len2; i++) { initializeItemNode.execute(inliningTarget, left, i + len1, getItemRightNode.execute(inliningTarget, right, i)); } + LoopNode.reportLoopCount(inliningTarget, len2); setLenNode.execute(inliningTarget, left, len1 + len2); return left; } @@ -2330,6 +2367,7 @@ static SequenceStorage doGeneric(SequenceStorage dest, SequenceStorage left, Seq for (int i = 0; i < len2; i++) { initializeItemNode.execute(inliningTarget, dest, i + len1, getItemRightNode.execute(inliningTarget, right, i)); } + LoopNode.reportLoopCount(inliningTarget, len1 + len2); setLenNode.execute(inliningTarget, dest, len1 + len2); return dest; } @@ -2608,7 +2646,7 @@ SequenceStorage doArrayBasedManaged(ArrayBasedSequenceStorage s, int times, int newLength = PythonUtils.multiplyExact(len, times); ArrayBasedSequenceStorage repeated = profiled.createEmpty(newLength); Object destArr = repeated.getInternalArrayObject(); - repeat(destArr, arr1, len, times); + repeat(inliningTarget, destArr, arr1, len, times); repeated.setNewLength(newLength); return repeated; } catch (OutOfMemoryError e) { @@ -2635,6 +2673,7 @@ SequenceStorage doGeneric(SequenceStorage s, int times, for (int i = 0; i < len; i++) { setItemNode.execute(inliningTarget, repeated, i, getItemNode.execute(inliningTarget, s, i)); } + LoopNode.reportLoopCount(inliningTarget, len); // read from destination since that is potentially faster for (int j = 1; j < times; j++) { @@ -2642,6 +2681,8 @@ SequenceStorage doGeneric(SequenceStorage s, int times, setItemNode.execute(inliningTarget, repeated, j * len + i, getDestItemNode.execute(inliningTarget, repeated, i)); } } + LoopNode.reportLoopCount(inliningTarget, times - 1); + LoopNode.reportLoopCount(inliningTarget, newLen - len); repeated.setNewLength(newLen); return repeated; @@ -2652,10 +2693,11 @@ SequenceStorage doGeneric(SequenceStorage s, int times, } } - private static void repeat(Object dest, Object src, int len, int times) { + private static void repeat(Node inliningTarget, Object dest, Object src, int len, int times) { for (int i = 0; i < times; i++) { PythonUtils.arraycopy(src, 0, dest, i * len, len); } + LoopNode.reportLoopCount(inliningTarget, times); } protected static boolean isInt(Object times) { @@ -2708,18 +2750,24 @@ public static int doByteStorage(ByteSequenceStorage s, byte item) { } @Specialization - public static int doIntStorage(IntSequenceStorage s, int item) { - return s.indexOfInt(item); + public static int doIntStorage(Node inliningTarget, IntSequenceStorage s, int item) { + int index = s.indexOfInt(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization - public static int doLongStorage(LongSequenceStorage s, long item) { - return s.indexOfLong(item); + public static int doLongStorage(Node inliningTarget, LongSequenceStorage s, long item) { + int index = s.indexOfLong(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization - public static int doDoubleStorage(DoubleSequenceStorage s, double item) { - return s.indexOfDouble(item); + public static int doDoubleStorage(Node inliningTarget, DoubleSequenceStorage s, double item) { + int index = s.indexOfDouble(item); + LoopNode.reportLoopCount(inliningTarget, index < 0 ? s.length() : index + 1); + return index; } @Specialization @@ -3330,21 +3378,23 @@ static SequenceStorage doNativeInt(Node inliningTarget, NativeIntSequenceStorage } @Specialization - static SequenceStorage doNativeBytes(NativeByteSequenceStorage s) { + static SequenceStorage doNativeBytes(Node inliningTarget, NativeByteSequenceStorage s) { byte[] bytes = new byte[s.length()]; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) GetNativeItemScalarNode.doNativeByte(s, i); } + LoopNode.reportLoopCount(inliningTarget, bytes.length); return new ByteSequenceStorage(bytes); } @Specialization - static SequenceStorage doNativeObjects(NativeObjectSequenceStorage s, + static SequenceStorage doNativeObjects(Node inliningTarget, NativeObjectSequenceStorage s, @Cached(inline = false) GetNativeItemScalarNode getItem) { Object[] objects = new Object[s.length()]; for (int i = 0; i < objects.length; i++) { objects[i] = getItem.execute(s, i); } + LoopNode.reportLoopCount(inliningTarget, objects.length); return new ObjectSequenceStorage(objects); } @@ -3355,6 +3405,7 @@ static SequenceStorage doForeign(Node inliningTarget, ForeignSequenceStorage s, for (int i = 0; i < objects.length; i++) { objects[i] = readNode.execute(inliningTarget, s, i); } + LoopNode.reportLoopCount(inliningTarget, objects.length); return new ObjectSequenceStorage(objects); } } @@ -3372,23 +3423,23 @@ public static Object[] executeUncached(SequenceStorage s) { } @Specialization - static Object[] doInt(IntSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doInt(Node inliningTarget, IntSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doDouble(DoubleSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doDouble(Node inliningTarget, DoubleSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doByte(ByteSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doByte(Node inliningTarget, ByteSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization - static Object[] doLong(LongSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doLong(Node inliningTarget, LongSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization @@ -3397,8 +3448,8 @@ static Object[] doObject(ObjectSequenceStorage storage) { } @Specialization - static Object[] doBool(BoolSequenceStorage storage) { - return storage.getCopyOfInternalArray(); + static Object[] doBool(Node inliningTarget, BoolSequenceStorage storage) { + return storage.getCopyOfInternalArray(inliningTarget); } @Specialization @@ -3412,12 +3463,13 @@ static Object[] doEmpty(@SuppressWarnings("unused") EmptySequenceStorage s) { } @Specialization - static Object[] doNative(NativeSequenceStorage s, + static Object[] doNative(Node inliningTarget, NativeSequenceStorage s, @Cached(inline = false) GetNativeItemScalarNode getNativeItemScalarNode) { Object[] result = new Object[s.length()]; for (int i = 0; i < s.length(); i++) { result[i] = getNativeItemScalarNode.execute(s, i); } + LoopNode.reportLoopCount(inliningTarget, result.length); return result; } } @@ -3704,6 +3756,7 @@ static void multipleSteps(SequenceStorage self, SliceInfo sinfo, memove.execute(inliningTarget, self, cur - i, cur + 1, lim); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, slicelen)); /*- Move the tail of the bytes, in one chunk */ cur = start + slicelen * step; if (cur < len) { @@ -3898,6 +3951,7 @@ private static Object[] materializeGeneric(Node inliningTarget, SequenceStorage for (int i = 0; i < barr.length; i++) { barr[i] = getItemNode.execute(inliningTarget, s, i); } + LoopNode.reportLoopCount(inliningTarget, barr.length); return barr; } @@ -4092,6 +4146,7 @@ protected static SequenceStorage doNativeObjectStorage(Node inliningTarget, Nati for (int i = storage.length(); i > index; i--) { writePtrArrayElement(storage.getPtr(), i, readPtrArrayElement(storage.getPtr(), i - 1)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) storage.length() - index))); Object promoted = ensurePythonObjectNode.execute(PythonContext.get(inliningTarget), value, false); writePtrArrayElement(storage.getPtr(), index, toNative.executeNewRef(inliningTarget, promoted)); storage.setNewLength(newLength); @@ -4107,6 +4162,7 @@ protected static SequenceStorage doNativeByteStorage(Node inliningTarget, Native for (int i = storage.length(); i > index; i--) { writeByteArrayElement(storage.getPtr(), i, readByteArrayElement(storage.getPtr(), i - 1)); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, (long) storage.length() - index))); writeByteArrayElement(storage.getPtr(), index, castToByteNode.execute(null, value)); storage.setNewLength(newLength); return storage; @@ -4259,7 +4315,7 @@ private SequenceStorage createStorageUninitialized(VirtualFrame frame, Node inli value = nextNode.execute(frame, inliningTarget, iterator); } catch (IteratorExhausted e) { LoopNode.reportLoopCount(this, i); - return SequenceStorageFactory.createStorage(PythonUtils.arrayCopyOf(elements, i)); + return SequenceStorageFactory.createStorage(inliningTarget, PythonUtils.arrayCopyOf(elements, i)); } if (i >= elements.length) { // Intentionally not profiled, because "size" can be reprofiled after this diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java index 65fe319642..f57858bfe1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SortNodes.java @@ -300,6 +300,7 @@ void sort(VirtualFrame frame, SequenceStorage storage, Object keyfunc, boolean r for (int i = 0; i < len; i++) { array[i] = getItemScalarNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, len); if (keyfunc instanceof PNone) { sortWithoutKey(frame, array, len, reverse, callContext); } else { @@ -308,6 +309,7 @@ void sort(VirtualFrame frame, SequenceStorage storage, Object keyfunc, boolean r for (int i = 0; i < len; i++) { setItemScalarNode.execute(inliningTarget, storage, i, array[i]); } + LoopNode.reportLoopCount(inliningTarget, len); } private void sortWithoutKey(VirtualFrame frame, Object[] array, int len, boolean reverse, CallContext callContext) { @@ -421,6 +423,7 @@ private void sortWithKey(VirtualFrame frame, Object[] array, int len, Object key } pairArray[reverse ? len - i - 1 : i] = new SortingPair(key, array[i]); } + LoopNode.reportLoopCount(this, len - 1); if (keySortComparator != null) { callSortWithKey(pairArray, len, keySortComparator); } else { @@ -449,6 +452,7 @@ private void sortWithKey(VirtualFrame frame, Object[] array, int len, Object key for (int i = 0; i < len; i++) { array[reverse ? len - i - 1 : i] = pairArray[i].value; } + LoopNode.reportLoopCount(this, len); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java index eea0ba1d95..c5b498b3c0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeBuiltins.java @@ -130,6 +130,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -320,6 +321,7 @@ int doGeneric(VirtualFrame frame, PDeque self, Object value, throw PRaiseNode.raiseStatic(this, RuntimeError, ErrorMessages.DEQUE_MUTATED_DURING_ITERATION); } } + LoopNode.reportLoopCount(inliningTarget, self.getSize()); return n; } } @@ -430,6 +432,7 @@ static int doWithIntSlice(VirtualFrame frame, PDeque self, Object value, int sta Object item = next(iterator); if (normStart <= idx) { if (eqNode.execute(frame, inliningTarget, item, value, RichCmpOp.Py_EQ)) { + LoopNode.reportLoopCount(inliningTarget, idx + 1); return idx; } if (startState != self.getState()) { @@ -572,6 +575,7 @@ Object doGeneric(VirtualFrame frame, PDeque self, Object value, Object removed = self.popLeft(); assert removed != null; DequeRotateNode.doRight(self, i); + LoopNode.reportLoopCount(inliningTarget, i + 1); return PNone.NONE; } else { // this is basically 'DequeRotateNode.doLeft(self, -1)' diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java index 5ee9041776..f2c0b6cc5c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeIterBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -67,6 +67,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -100,8 +101,13 @@ static PDequeIter doGeneric(VirtualFrame frame, @SuppressWarnings("unused") Obje PDequeIter dequeIter = PFactory.createDequeIter(language, (PDeque) deque); if (indexNoneProfile.profile(inliningTarget, indexObj != PNone.NO_VALUE)) { int index = castToJavaIntExactNode.execute(inliningTarget, toIndexNode.execute(frame, inliningTarget, indexObj)); - for (int i = 0; i < index; i++) { - getNextNode.execute(dequeIter); + int i = 0; + try { + for (; i < index; i++) { + getNextNode.execute(dequeIter); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } } return dequeIter; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java index 9918a13f9c..361d4164ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/deque/DequeRevIterBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -67,6 +67,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -100,8 +101,13 @@ static PDequeIter doGeneric(VirtualFrame frame, @SuppressWarnings("unused") Obje PDequeIter dequeIter = PFactory.createDequeRevIter(language, (PDeque) deque); if (indexNoneProfile.profile(inliningTarget, indexObj != PNone.NO_VALUE)) { int index = castToJavaIntExactNode.execute(inliningTarget, toIndexNode.execute(frame, inliningTarget, indexObj)); - for (int i = 0; i < index; i++) { - getNextNode.execute(dequeIter); + int i = 0; + try { + for (; i < index; i++) { + getNextNode.execute(dequeIter); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } } return dequeIter; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java index 5add0517ba..b31b48637a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/BaseExceptionGroupBuiltins.java @@ -111,6 +111,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -196,6 +197,7 @@ static PBaseExceptionGroup doManaged(VirtualFrame frame, Object cls, Object mess throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.ITEM_D_OF_SECOND_ARGUMENT_EXCEPTIONS_IS_NOT_AN_EXCEPTION, i); } } + LoopNode.reportLoopCount(inliningTarget, exceptions.length); if (isSameTypeNode.execute(inliningTarget, cls, PythonBuiltinClassType.PBaseExceptionGroup)) { if (!nestedBaseExceptions) { /* diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java index a401c07a98..24d9b48165 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java @@ -247,7 +247,7 @@ public int getNumber() { } @TruffleBoundary - private static OSErrorEnum fromMessage(TruffleString message, TruffleString.EqualNode eqNode) { + private static OSErrorEnum fromMessage(TruffleString message) { if (message == null) { return null; } @@ -255,14 +255,15 @@ private static OSErrorEnum fromMessage(TruffleString message, TruffleString.Equa if (oserror.getMessage() == null) { continue; } - if (eqNode.execute(message, oserror.getMessage(), TS_ENCODING)) { + + if (message.equalsUncached(oserror.getMessage(), TS_ENCODING)) { return oserror; } for (TruffleString altMessage : oserror.alternativeMessages) { if (altMessage == null) { continue; } - if (eqNode.execute(message, altMessage, TS_ENCODING)) { + if (message.equalsUncached(altMessage, TS_ENCODING)) { return oserror; } } @@ -281,7 +282,7 @@ public static OSErrorEnum fromNumber(int number) { return null; } - public static ErrorAndMessagePair fromException(Exception e, TruffleString.EqualNode eqNode) { + public static ErrorAndMessagePair fromException(Exception e) { if (e instanceof IOException) { if (e instanceof NoSuchFileException || e instanceof FileNotFoundException) { return new ErrorAndMessagePair(OSErrorEnum.ENOENT, OSErrorEnum.ENOENT.getMessage()); @@ -305,14 +306,14 @@ public static ErrorAndMessagePair fromException(Exception e, TruffleString.Equal // specific error numbers like in the glob module: failing to match the correct // error number of 40 (link loop) breaks that module's code TruffleString reason = getReason((FileSystemException) e); - OSErrorEnum oserror = OSErrorEnum.fromMessage(reason, eqNode); + OSErrorEnum oserror = OSErrorEnum.fromMessage(reason); if (oserror == null) { return new ErrorAndMessagePair(OSErrorEnum.EIO, reason); } else { return new ErrorAndMessagePair(oserror, oserror.getMessage()); } } else { // Generic IOException - OSErrorEnum oserror = tryFindErrnoFromMessage(e, eqNode); + OSErrorEnum oserror = tryFindErrnoFromMessage(e); if (oserror == null) { return new ErrorAndMessagePair(OSErrorEnum.EIO, getMessage(e)); } else { @@ -360,13 +361,13 @@ private static TruffleString getReason(FileSystemException e) { } @TruffleBoundary - private static OSErrorEnum tryFindErrnoFromMessage(Exception e, TruffleString.EqualNode eqNode) { + private static OSErrorEnum tryFindErrnoFromMessage(Exception e) { String message = e.getMessage(); Matcher m = ERRNO_PATTERN.matcher(message); if (m.find()) { return fromNumber(Integer.parseInt(m.group(1))); } - return OSErrorEnum.fromMessage(toTruffleStringUncached(message), eqNode); + return OSErrorEnum.fromMessage(toTruffleStringUncached(message)); } @ValueType diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java index 0c1d2072c0..9aa81b46bc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseExceptionGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -45,7 +45,7 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; -public class PBaseExceptionGroup extends PBaseException { +public final class PBaseExceptionGroup extends PBaseException { private final TruffleString message; private final Object[] exceptions; private PException parent; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java index 8a25b39ce5..858b8102b5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java @@ -116,6 +116,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.object.Shape; @@ -1050,11 +1051,13 @@ static PTuple get(Object selfObj, ++exponent; mantissa /= 2; } + LoopNode.reportLoopCount(inliningTarget, exponent); } else if (mantissa < 0.5) { while (mantissa < 0.5) { --exponent; mantissa *= 2; } + LoopNode.reportLoopCount(inliningTarget, -exponent); } if (neg) { mantissa = -mantissa; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java index 423c5d4b8e..1bde08c560 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java @@ -92,6 +92,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -317,6 +318,7 @@ protected Object doIt(VirtualFrame frame, Object object, memberString = switchEncodingNode.execute(memberString, TS_ENCODING); addNode.execute(frame, attributes, memberString); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, Math.max(0L, size))); } catch (UnsupportedMessageException | InvalidArrayIndexException e) { throw CompilerDirectives.shouldNotReachHere(e); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java index 10dd053c17..149bb989f3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameLocalsProxyBuiltins.java @@ -164,12 +164,14 @@ private static PDict snapshot(PFrameLocalsProxy self, PythonLanguage language, N PDict result = PFactory.createDict(language); BytecodeFrame bytecodeFrame = self.getBytecodeFrame(); BytecodeDSLFrameInfo info = bytecodeFrame == null ? null : (BytecodeDSLFrameInfo) bytecodeFrame.getFrameDescriptorInfo(); - for (int i = 0; info != null && i < info.getVariableCount(); i++) { + int varCount = info == null ? 0 : info.getVariableCount(); + for (int i = 0; i < varCount; i++) { Object value = getSlotValue(self, i); if (value != null) { result.setDictStorage(setItem.execute(inliningTarget, result.getDictStorage(), info.getVariableName(i), value)); } } + LoopNode.reportLoopCount(inliningTarget, varCount); PDict extra = self.getFrame().getExtraLocals(); if (extra != null) { result.update(extra); @@ -289,11 +291,13 @@ private static int count(PFrameLocalsProxy self, Node inliningTarget, HashingSto int count = 0; BytecodeFrame bytecodeFrame = self.getBytecodeFrame(); BytecodeDSLFrameInfo info = bytecodeFrame == null ? null : (BytecodeDSLFrameInfo) bytecodeFrame.getFrameDescriptorInfo(); - for (int i = 0; info != null && i < info.getVariableCount(); i++) { + int varCount = info == null ? 0 : info.getVariableCount(); + for (int i = 0; i < varCount; i++) { if (getSlotValue(self, i) != null) { count++; } } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, varCount)); PDict extra = self.getFrame().getExtraLocals(); return count + (extra == null ? 0 : storageLen.execute(inliningTarget, extra.getDictStorage())); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java index 4cd53ffff2..5767768938 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/IntNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -181,10 +181,14 @@ static byte[] doPInt(Node inliningTarget, PInt value, int size, boolean bigEndia @GenerateInline(inlineByDefault = true) @GenerateUncached public abstract static class PyLongFromByteArray extends Node { - public abstract Object execute(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed); + public abstract Object execute(Node inliningTarget, byte[] data, int offset, int length, boolean littleEndian, boolean signed); - public final Object executeCached(byte[] data, boolean littleEndian, boolean signed) { - return execute(this, data, littleEndian, signed); + public final Object execute(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed) { + return execute(inliningTarget, data, 0, data.length, littleEndian, signed); + } + + public final Object executeCached(byte[] data, int offset, int length, boolean littleEndian, boolean signed) { + return execute(this, data, offset, length, littleEndian, signed); } public static Object executeUncached(byte[] data, boolean littleEndian, boolean signed) { @@ -192,37 +196,65 @@ public static Object executeUncached(byte[] data, boolean littleEndian, boolean } @Specialization - static Object doOther(Node inliningTarget, byte[] data, boolean littleEndian, boolean signed, + static Object doOther(Node inliningTarget, byte[] data, int offset, int length, boolean littleEndian, boolean signed, @Cached InlinedBranchProfile fastPath1, @Cached InlinedBranchProfile fastPath2, @Cached InlinedBranchProfile fastPath4, @Cached InlinedBranchProfile fastPath8, + @Cached InlinedBranchProfile variablePath, + @Cached InlinedBranchProfile fastPathVariable, + @Cached InlinedBranchProfile overlong, @Cached InlinedBranchProfile generic, @Cached PRaiseNode raiseNode) { NumericSupport support = littleEndian ? NumericSupport.littleEndian() : NumericSupport.bigEndian(); if (signed) { - switch (data.length) { + switch (length) { case 1 -> { fastPath1.enter(inliningTarget); - return (int) support.getByte(data, 0); + return (int) support.getByte(data, offset); } case 2 -> { fastPath2.enter(inliningTarget); - return (int) support.getShort(data, 0); + return (int) support.getShort(data, offset); } case 4 -> { fastPath4.enter(inliningTarget); - return support.getInt(data, 0); + return support.getInt(data, offset); } case 8 -> { fastPath8.enter(inliningTarget); - return support.getLong(data, 0); + return support.getLong(data, offset); } } } + variablePath.enter(inliningTarget); + int remaining = length; + int index = littleEndian ? offset + length - 1 : offset; + int step = littleEndian ? -1 : 1; + boolean negative = signed && length > 0 && data[index] < 0; + if (remaining > Long.BYTES) { + overlong.enter(inliningTarget); + // Ignore redundant sign or zero extension beyond the width of a long. + byte padding = (byte) (negative ? -1 : 0); + while (remaining > Long.BYTES && data[index] == padding) { + index += step; + remaining--; + } + } + // For eight bytes, the remaining sign bit must agree with the original sign. + // This also excludes unsigned values greater than Long.MAX_VALUE. + if (remaining < Long.BYTES || (remaining == Long.BYTES && (data[index] < 0) == negative)) { + fastPathVariable.enter(inliningTarget); + long value = negative ? -1L : 0L; + for (int i = 0; i < remaining; i++) { + value = (value << Byte.SIZE) | (data[index] & 0xffL); + index += step; + } + return value; + } generic.enter(inliningTarget); try { - BigInteger integer = support.getBigInteger(data, signed); + BigInteger integer = support.getBigInteger(data, offset, length, signed); if (PInt.bigIntegerFitsInLong(integer)) { long longValue = PInt.longValue(integer); return PInt.isIntRange(longValue) ? (int) longValue : longValue; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java index 921d1ec4ab..34c53e7714 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorNodes.java @@ -98,6 +98,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -358,6 +359,7 @@ static Object[] doString(Object iterableObj, // TODO: GR-37219: use SubstringNode with lazy=true? result[i++] = fromCodePointNode.execute(nextNode.execute(it, TS_ENCODING), TS_ENCODING, true); } + LoopNode.reportLoopCount(inliningTarget, result.length); return result; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java index 563041a21f..615e340608 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/ZipBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2014, Regents of the University of California * * All rights reserved. @@ -151,13 +151,18 @@ static Object doNext(VirtualFrame frame, PZip self, @Cached CallSlotTpIterNextNode callIterNext) { Object[] iterators = self.getIterators(); Object[] tupleElements = new Object[iterators.length]; - for (int i = 0; i < iterators.length; i++) { - Object it = iterators[i]; - /* - * Not using PyIterNext because the non-strict version should pass through existing - * StopIteration - */ - tupleElements[i] = callIterNext.execute(frame, inliningTarget, getSlots.execute(inliningTarget, it).tp_iternext(), it); + int i = 0; + try { + for (; i < iterators.length; i++) { + Object it = iterators[i]; + /* + * Not using PyIterNext because the non-strict version should pass through existing + * StopIteration + */ + tupleElements[i] = callIterNext.execute(frame, inliningTarget, getSlots.execute(inliningTarget, it).tp_iternext(), it); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(language, tupleElements); } @@ -175,6 +180,7 @@ static Object doNext(VirtualFrame frame, PZip self, try { tupleElements[i] = nextNode.execute(frame, inliningTarget, iterators[i]); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, i + 1); if (i > 0) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.ZIP_ARG_D_IS_SHORTER_THEN_ARG_SD, i + 1, i == 1 ? " " : "s 1-", i); } @@ -189,6 +195,7 @@ static Object doNext(VirtualFrame frame, PZip self, throw e; } } + LoopNode.reportLoopCount(inliningTarget, iterators.length); return PFactory.createTuple(language, tupleElements); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java index 0ce339cc57..0ece90105d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/BatchedBuiltins.java @@ -73,6 +73,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PBatched) @@ -140,32 +141,36 @@ static Object next(VirtualFrame frame, PBatched bo, if (bo.it == null) { throw raiseNode.raiseStopIteration(inliningTarget, null); } - int i; + int i = 0; int n = bo.batchSize; Object it = bo.it; Object[] items = new Object[n]; - for (i = 0; i < n; i++) { - try { + try { + for (; i < n; i++) { try { - items[i] = nextNode.execute(frame, inliningTarget, it); - } catch (IteratorExhausted e) { - if (i == 0) { - bo.it = null; - return TpIterNextBuiltin.iteratorExhausted(); + try { + items[i] = nextNode.execute(frame, inliningTarget, it); + } catch (IteratorExhausted e) { + if (i == 0) { + bo.it = null; + return TpIterNextBuiltin.iteratorExhausted(); + } + if (bo.isStrict()) { + bo.it = null; + throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BATCHED_INCOMPLETE_BATCH); + } + items = PythonUtils.arrayCopyOf(items, i); + break; } - if (bo.isStrict()) { - bo.it = null; - throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BATCHED_INCOMPLETE_BATCH); - } - items = PythonUtils.arrayCopyOf(items, i); - break; + } catch (PException e) { + /* Handle input raised an exception other than StopIteration */ + bo.it = null; + throw e; } - } catch (PException e) { - /* Handle input raised an exception other than StopIteration */ - bo.it = null; - throw e; } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(language, items); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java index d42d9186d9..42a4a7335e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/CombinationsBuiltins.java @@ -91,6 +91,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -142,6 +143,7 @@ static Object construct(VirtualFrame frame, Object cls, Object iterable, int r, for (int i = 0; indicesLoopProfile.inject(i < r); i++) { indices[i] = i; } + LoopNode.reportLoopCount(inliningTarget, r); self.setIndices(indices); self.setR(r); self.setLastResult(null); @@ -182,6 +184,7 @@ static Object nextNoResult(PAbstractCombinations self, int idx = self.getIndices()[i]; result[i] = self.getPool()[idx]; } + LoopNode.reportLoopCount(inliningTarget, result.length); self.setLastResult(result); return PFactory.createTuple(language, result); } @@ -216,6 +219,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se while (i >= 0 && self.getIndices()[i] == self.getMaximum(poolLen, i)) { i -= 1; } + LoopNode.reportLoopCount(inliningTarget, (int) ((long) self.getR() - i - 1)); // If i is negative, then the indices are all at their maximum value and we're done if (i < 0) { @@ -230,6 +234,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se for (int j = i + 1; indexLoopProfile.inject(inliningTarget, j < self.getR()); j++) { self.getIndices()[j] = self.maxIndex(j); } + LoopNode.reportLoopCount(inliningTarget, self.getR() - i - 1); // Update the result for the new indices starting with i, the leftmost index that // changed @@ -239,6 +244,7 @@ private static Object nextInternal(Node inliningTarget, PAbstractCombinations se Object elem = self.getPool()[index]; result[j] = elem; } + LoopNode.reportLoopCount(inliningTarget, self.getR() - i); self.setLastResult(result); return PFactory.createTuple(PythonLanguage.get(inliningTarget), result); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java index c37d68f1a9..afbcb5ccb3 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/PermutationsBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -221,29 +221,36 @@ static Object next(PPermutations self, for (int i = 0; resultLoopProfile.inject(inliningTarget, i < r); i++) { result[i] = pool[indices[i]]; } + LoopNode.reportLoopCount(inliningTarget, r); int[] cycles = self.getCycles(); int i = r - 1; - while (mainLoopProfile.profile(inliningTarget, i >= 0)) { - int j = cycles[i] - 1; - if (j > 0) { - jProfile.enter(inliningTarget); - cycles[i] = j; - int tmp = indices[i]; - indices[i] = indices[indices.length - j]; - indices[indices.length - j] = tmp; - return PFactory.createTuple(language, result); - } - cycles[i] = indices.length - i; - int n1 = indices.length - 1; - assert n1 >= 0; - int num = indices[i]; - shiftIndicesProfile.profileCounted(inliningTarget, n1 - i); - for (int k = i; shiftIndicesProfile.profile(inliningTarget, k < n1); k++) { - indices[k] = indices[k + 1]; + try { + while (mainLoopProfile.profile(inliningTarget, i >= 0)) { + int j = cycles[i] - 1; + if (j > 0) { + jProfile.enter(inliningTarget); + cycles[i] = j; + int tmp = indices[i]; + indices[i] = indices[indices.length - j]; + indices[indices.length - j] = tmp; + return PFactory.createTuple(language, result); + } + cycles[i] = indices.length - i; + int n1 = indices.length - 1; + assert n1 >= 0; + int num = indices[i]; + shiftIndicesProfile.profileCounted(inliningTarget, n1 - i); + for (int k = i; shiftIndicesProfile.profile(inliningTarget, k < n1); k++) { + indices[k] = indices[k + 1]; + } + indices[n1] = num; + i = i - 1; } - indices[n1] = num; - i = i - 1; + } finally { + // approximation + long iterations = 2 * (r - 1L - i) * (indices.length - r); + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, iterations)); } self.setStopped(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java index 201ba903be..ca224a80aa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ProductBuiltins.java @@ -115,7 +115,7 @@ static Object constructNoneRepeat(VirtualFrame frame, Object cls, Object[] itera @SuppressWarnings("unused") @Cached.Shared("typeNode") @Cached TypeNodes.IsTypeNode isTypeNode, @Cached.Shared @Cached TypeNodes.GetInstanceShape getInstanceShape) { PProduct self = PFactory.createProduct(cls, getInstanceShape.execute(cls)); - constructOneRepeat(frame, self, iterables, toArrayNode); + constructOneRepeat(frame, inliningTarget, self, iterables, toArrayNode); return self; } @@ -145,27 +145,27 @@ static Object constructRepeat(VirtualFrame frame, Object cls, Object[] iterables self.setStopped(false); } else if (repeatInt == 1) { oneProfile.enter(inliningTarget); - constructOneRepeat(frame, self, iterables, toArrayNode); + constructOneRepeat(frame, inliningTarget, self, iterables, toArrayNode); } else { genericProfile.enter(inliningTarget); - Object[][] lists = unpackIterables(frame, iterables, toArrayNode); + Object[][] lists = unpackIterables(frame, inliningTarget, iterables, toArrayNode); Object[][] gears = new Object[lists.length * repeatInt][]; loopProfile.profileCounted(inliningTarget, repeatInt); LoopNode.reportLoopCount(inliningTarget, repeatInt); for (int i = 0; loopProfile.inject(inliningTarget, i < repeatInt); i++) { PythonUtils.arraycopy(lists, 0, gears, i * lists.length, lists.length); } - construct(self, gears); + construct(inliningTarget, self, gears); } return self; } - private static void constructOneRepeat(VirtualFrame frame, PProduct self, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { - Object[][] gears = unpackIterables(frame, iterables, toArrayNode); - construct(self, gears); + private static void constructOneRepeat(VirtualFrame frame, Node inliningTarget, PProduct self, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { + Object[][] gears = unpackIterables(frame, inliningTarget, iterables, toArrayNode); + construct(inliningTarget, self, gears); } - private static void construct(PProduct self, Object[][] gears) { + private static void construct(Node inliningTarget, PProduct self, Object[][] gears) { self.setGears(gears); for (int i = 0; i < gears.length; i++) { if (gears[i].length == 0) { @@ -175,16 +175,18 @@ private static void construct(PProduct self, Object[][] gears) { return; } } + LoopNode.reportLoopCount(inliningTarget, gears.length); self.setIndices(new int[gears.length]); self.setLst(null); self.setStopped(false); } - private static Object[][] unpackIterables(VirtualFrame frame, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { + private static Object[][] unpackIterables(VirtualFrame frame, Node inliningTarget, Object[] iterables, IteratorNodes.ToArrayNode toArrayNode) { Object[][] lists = new Object[iterables.length][]; for (int i = 0; i < lists.length; i++) { lists[i] = toArrayNode.execute(frame, iterables[i]); } + LoopNode.reportLoopCount(inliningTarget, lists.length); return lists; } @@ -220,6 +222,7 @@ static Object next(PProduct self, for (int i = 0; loopProfile.inject(inliningTarget, i < lst.length); i++) { lst[i] = self.getGears()[i][0]; } + LoopNode.reportLoopCount(inliningTarget, lst.length); self.setLst(lst); return PFactory.createTuple(language, lst); } @@ -275,19 +278,23 @@ private static void rotatePreviousGear(Node inliningTarget, PProduct self, Inlin indices[x] = 0; x = x - 1; // the outer loop runs as long as we have a carry - while (loopProfile.profile(inliningTarget, x >= 0)) { - Object[] gear = gears[x]; - int index = indices[x] + 1; - if (index < gear.length) { - // no carry: done - doneProfile.enter(inliningTarget); - lst[x] = gear[index]; - indices[x] = index; - return; + try { + while (loopProfile.profile(inliningTarget, x >= 0)) { + Object[] gear = gears[x]; + int index = indices[x] + 1; + if (index < gear.length) { + // no carry: done + doneProfile.enter(inliningTarget); + lst[x] = gear[index]; + indices[x] = index; + return; + } + lst[x] = gear[0]; + indices[x] = 0; + x = x - 1; } - lst[x] = gear[0]; - indices[x] = 0; - x = x - 1; + } finally { + LoopNode.reportLoopCount(inliningTarget, gears.length - 2 - x); } self.setLst(null); self.setStopped(true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java index 7ef9362f44..192306692d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/ZipLongestBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -163,28 +163,33 @@ static Object next(VirtualFrame frame, PZipLongest self, Object fillValue = isNullFillProfile.profile(inliningTarget, isNullFillValue(self)) ? PNone.NONE : self.getFillValue(); Object[] result = new Object[self.getItTuple().length]; loopProfile.profileCounted(inliningTarget, result.length); - for (int i = 0; loopProfile.inject(inliningTarget, i < result.length); i++) { - Object it = self.getItTuple()[i]; - Object item; - if (noItProfile.profile(inliningTarget, it == PNone.NONE)) { - item = fillValue; - } else { - try { - item = nextNode.execute(frame, inliningTarget, it); - } catch (IteratorExhausted e) { - self.setNumActive(self.getNumActive() - 1); - if (noActiveProfile.profile(inliningTarget, self.getNumActive() == 0)) { - throw iteratorExhausted(); - } else { - item = fillValue; - self.getItTuple()[i] = PNone.NONE; + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < result.length); i++) { + Object it = self.getItTuple()[i]; + Object item; + if (noItProfile.profile(inliningTarget, it == PNone.NONE)) { + item = fillValue; + } else { + try { + item = nextNode.execute(frame, inliningTarget, it); + } catch (IteratorExhausted e) { + self.setNumActive(self.getNumActive() - 1); + if (noActiveProfile.profile(inliningTarget, self.getNumActive() == 0)) { + throw iteratorExhausted(); + } else { + item = fillValue; + self.getItTuple()[i] = PNone.NONE; + } + } catch (PException e) { + self.setNumActive(0); + throw e; } - } catch (PException e) { - self.setNumActive(0); - throw e; } + result[i] = item; } - result[i] = item; + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return PFactory.createTuple(PythonLanguage.get(inliningTarget), result); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java index b699d11c46..ccc2edb21b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/list/ListBuiltins.java @@ -225,6 +225,7 @@ public TruffleString repr(VirtualFrame frame, Object self, Object value = getItem.execute(storage, index); appendStringNode.execute(buf, reprNode.execute(frame, inliningTarget, value)); } + LoopNode.reportLoopCount(inliningTarget, length); appendStringNode.execute(buf, T_RBRACKET); return toStringNode.execute(buf); } finally { @@ -260,6 +261,7 @@ static PNone listRange(PList list, PIntRange range, array[i] = value; value += step; } + LoopNode.reportLoopCount(inliningTarget, len); list.setSequenceStorage(new IntSequenceStorage(array)); return PNone.NONE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java index f83a46fc57..39fdea5365 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/map/MapBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -77,6 +77,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; @@ -115,6 +116,7 @@ static PMap doit(VirtualFrame frame, Object cls, Object[] args, PKeyword[] keywo for (int i = 0; loopProfile.inject(inliningTarget, i < iterators.length); i++) { iterators[i] = getIter.execute(frame, inliningTarget, args[i + 1]); } + LoopNode.reportLoopCount(inliningTarget, iterators.length); map.setIterators(iterators); return map; } @@ -145,10 +147,15 @@ static Object doNext(VirtualFrame frame, PMap self, Object[] iterators = self.getIterators(); Object[] arguments = new Object[iterators.length]; loopProfile.profileCounted(inliningTarget, iterators.length); - for (int i = 0; loopProfile.inject(inliningTarget, i < iterators.length); i++) { - Object iterator = iterators[i]; - TpSlot iternext = getSlots.execute(inliningTarget, iterator).tp_iternext(); - arguments[i] = callTpIternext.execute(frame, inliningTarget, iternext, iterator); + int i = 0; + try { + for (; loopProfile.inject(inliningTarget, i < iterators.length); i++) { + Object iterator = iterators[i]; + TpSlot iternext = getSlots.execute(inliningTarget, iterator).tp_iternext(); + arguments[i] = callTpIternext.execute(frame, inliningTarget, iternext, iterator); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } return callNode.execute(frame, self.getFunction(), arguments); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java index b68a8c7486..3b1bc39d04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewBuiltins.java @@ -129,6 +129,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -301,6 +302,7 @@ static void setitem(VirtualFrame frame, PMemoryView self, PSlice slice, Object o MemoryViewNodes.MemoryPointer destPtr = pointerLookupNode.execute(frame, destView, i); writeBytesAtNode.execute(inliningTarget, srcBytes, i * itemsize, itemsize, self, destPtr.ptr, destPtr.offset); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, destView.getBufferShape()[0])); } finally { releaseNode.execute(frame, destView); } @@ -688,6 +690,7 @@ private static int[] shapeFromStorage(VirtualFrame frame, Node inliningTarget, S throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MEMORYVIEW_CAST_ELEMENTS_MUST_BE_POSITIVE_INTEGERS); } } + LoopNode.reportLoopCount(inliningTarget, ndim); return shape; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java index 2fcbda6741..d259aca3b5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/memoryview/MemoryViewNodes.java @@ -90,6 +90,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; @@ -130,7 +131,7 @@ public static int executeUncached(int ndim, int itemsize, int[] shape, int[] str } @Specialization - static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] suboffsets) { + static int compute(Node inliningTarget, int ndim, int itemsize, int[] shape, int[] strides, int[] suboffsets) { if (ndim == 0) { return PMemoryView.FLAG_C | PMemoryView.FLAG_FORTRAN | PMemoryView.FLAG_SCALAR; } else if (suboffsets != null) { @@ -146,6 +147,7 @@ static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] sub } expectedStride *= dim; } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, ndim)); expectedStride = itemsize; for (int i = 0; i < ndim; i++) { int dim = shape[i]; @@ -155,6 +157,7 @@ static int compute(int ndim, int itemsize, int[] shape, int[] strides, int[] sub } expectedStride *= dim; } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, ndim)); return flags; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index 0134458d6e..86fbf6dfb0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -65,7 +65,7 @@ import static com.oracle.graal.python.runtime.PosixConstants.MAP_SHARED; import static com.oracle.graal.python.runtime.PosixConstants.PROT_READ; import static com.oracle.graal.python.runtime.PosixConstants.PROT_WRITE; -import static com.oracle.graal.python.runtime.PosixSupportLibrary.ST_SIZE; +import static com.oracle.graal.python.runtime.PosixSupport.ST_SIZE; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; @@ -75,8 +75,8 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.ArgumentClinic; import com.oracle.graal.python.annotations.ArgumentClinic.ClinicConversion; -import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.annotations.Builtin; +import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.annotations.Slot; import com.oracle.graal.python.annotations.Slot.SlotKind; import com.oracle.graal.python.annotations.Slot.SlotSignature; @@ -134,8 +134,7 @@ import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.nativeaccess.NativeAccessSupport; import com.oracle.graal.python.runtime.nativeaccess.NativeContext; @@ -154,6 +153,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -170,13 +170,13 @@ protected List> getNodeFa return MMapBuiltinsFactory.getFactories(); } - private static byte[] readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupportLibrary posixLib, Object posixSupport, long pos, int len, + private static byte[] readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupport posixSupport, long pos, int len, PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { assert len > 0; assert pos + len <= self.getLength(); byte[] buffer = new byte[len]; - posixLib.mmapReadBytes(posixSupport, self.getPosixSupportHandle(), pos, buffer, buffer.length); + posixSupport.mmapReadBytes(self.getPosixSupportHandle(), pos, buffer, buffer.length); return buffer; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -214,7 +214,6 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object tagname, Object trackFdArg, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixSupport, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TypeNodes.GetInstanceShape getInstanceShape, @Exclusive @Cached CastToTruffleStringNode castTagnameNode, @@ -271,11 +270,11 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj // For file mappings we use fstat to validate the length or to initialize the length if // it is 0 meaning that we should find it out for the user long length = lengthIn; - PosixSupport posixSupport1 = PosixSupport.get(inliningTarget); + PosixSupport posixSupport = PosixSupport.get(inliningTarget); if (fd != ANONYMOUS_FD) { long[] fstatResult = null; try { - fstatResult = posixSupport.fstat(posixSupport1, fd); + fstatResult = posixSupport.fstat(fd); } catch (PosixException ignored) { } if (fstatResult != null && length == 0) { @@ -301,7 +300,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj // MAP_ANONYMOUS, maybe this can be detected and handled by the POSIX layer } else if (mmapArgs.trackFd()) { try { - trackedFd = posixSupport.dup(posixSupport1, fd); + trackedFd = posixSupport.dup(fd); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -311,11 +310,11 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, Obj Object mmapHandle; try { - mmapHandle = posixSupport.mmap(posixSupport1, length, prot, flags, fd, offset, mmapTagname); + mmapHandle = posixSupport.mmap(inliningTarget, length, prot, flags, fd, offset, mmapTagname); } catch (PosixException e) { if (trackedFd != ANONYMOUS_FD) { try { - posixSupport.close(posixSupport1, trackedFd); + posixSupport.close(trackedFd); } catch (PosixException ignored) { } } @@ -379,12 +378,11 @@ static PBytes doInt(VirtualFrame frame, PMMap self, int index, @Bind Node inliningTarget, @Bind PythonContext context, @Cached PRaiseNode raiseNode, - @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib) { + @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long len = self.getLength(); checkBounds(inliningTarget, raiseNode, MMAP_INDEX_OUT_OF_RANGE, index, len); try { - byte b = posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), index); + byte b = context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), index); // CPython indeed returns bytes object from sq_item, although it returns single byte // value as integer from mp_subscript, see, e.g.: `for i in mmap_object: print(i)` return PFactory.createBytes(context.getLanguage(inliningTarget), new byte[]{b}); @@ -403,7 +401,6 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, @Bind Node inliningTarget, @Bind PythonContext context, @Exclusive @Cached InlinedConditionProfile negativeIndexProfile, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PyLongAsLongNode asLongNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Exclusive @Cached PRaiseNode raiseNode) { @@ -412,7 +409,7 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, long idx = negativeIndexProfile.profile(inliningTarget, i < 0) ? i + len : i; checkBounds(inliningTarget, raiseNode, MMAP_INDEX_OUT_OF_RANGE, idx, len); try { - return posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), idx) & 0xFF; + return context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), idx) & 0xFF; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -422,7 +419,6 @@ static int doSingle(VirtualFrame frame, PMMap self, Object idxObj, static Object doSlice(VirtualFrame frame, PMMap self, PSlice idx, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Exclusive @Cached InlinedConditionProfile emptyProfile, @Cached CoerceToIntSlice sliceCast, @Cached ComputeIndices compute, @@ -435,7 +431,7 @@ static Object doSlice(VirtualFrame frame, PMMap self, PSlice idx, if (emptyProfile.profile(inliningTarget, len == 0)) { return PFactory.createEmptyBytes(context.getLanguage(inliningTarget)); } - byte[] result = readBytes(frame, inliningTarget, self, posixSupportLib, context.getPosixSupport(), info.start, len, constructAndRaiseNode); + byte[] result = readBytes(frame, inliningTarget, self, context.getPosixSupport(), info.start, len, constructAndRaiseNode); return PFactory.createBytes(context.getLanguage(inliningTarget), result); } catch (OverflowException e) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.OverflowError, e); @@ -451,7 +447,6 @@ public abstract static class SetItemNode extends SqAssItemBuiltinNode { static void doSingle(VirtualFrame frame, PMMap self, int index, Object val, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, @Cached PyBytesCheckNode checkNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -474,7 +469,7 @@ static void doSingle(VirtualFrame frame, PMMap self, int index, Object val, } byte b = bufferLib.readByte(val, 0); try { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), index, b); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), index, b); } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); } @@ -489,7 +484,6 @@ public abstract static class SetSubscriptNode extends MpAssSubscriptBuiltinNode static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object valueObj, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PyIndexCheckNode checkNode, @Cached PyNumberAsSizeNode asSizeNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -522,7 +516,7 @@ static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object value throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, MMAP_ITEM_VALUE_MUST_BE_IN_RANGE); } try { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), idx, (byte) value); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), idx, (byte) value); } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); } @@ -533,7 +527,6 @@ static void doSingle(VirtualFrame frame, PMMap self, Object idxObj, Object value static void doSlice(VirtualFrame frame, PMMap self, PSlice slice, Object valueObj, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary acquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Cached SliceNodes.SliceUnpack sliceUnpack, @@ -566,12 +559,13 @@ static void doSlice(VirtualFrame frame, PMMap self, PSlice slice, Object valueOb if (info.sliceLength > 0) { try { if (step1Profile.profile(inliningTarget, info.step == 1)) { - posixSupportLib.mmapWriteBytes(context.getPosixSupport(), self.getPosixSupportHandle(), + context.getPosixSupport().mmapWriteBytes(self.getPosixSupportHandle(), info.start, bufferLib.getInternalOrCopiedByteArray(buffer), bufferLen); } else { for (int cur = info.start, i = 0; i < info.sliceLength; cur += info.step, i++) { - posixSupportLib.mmapWriteByte(context.getPosixSupport(), self.getPosixSupportHandle(), cur, bufferLib.readByte(buffer, i)); + context.getPosixSupport().mmapWriteByte(self.getPosixSupportHandle(), cur, bufferLib.readByte(buffer, i)); } + LoopNode.reportLoopCount(inliningTarget, info.sliceLength); } } catch (PosixException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, ex); @@ -623,9 +617,8 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization static PNone close(PMMap self, - @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib) { - self.close(posixSupportLib, context.getPosixSupport()); + @Bind PythonContext context) { + self.close(context.getPosixSupport()); return PNone.NONE; } } @@ -648,7 +641,6 @@ abstract static class SizeNode extends PythonBuiltinNode { static long size(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupport, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (self.isClosed()) { @@ -658,7 +650,7 @@ static long size(VirtualFrame frame, PMMap self, return self.getLength(); } try { - return posixSupport.fstat(context.getPosixSupport(), self.getFd())[ST_SIZE]; + return context.getPosixSupport().fstat(self.getFd())[ST_SIZE]; } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -704,14 +696,13 @@ abstract static class ReadByteNode extends PythonUnaryBuiltinNode { static int readByte(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixSupportLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { if (self.getPos() >= self.getLength()) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, READ_BYTE_OUT_OF_RANGE); } try { - byte res = posixSupportLib.mmapReadByte(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos()); + byte res = context.getPosixSupport().mmapReadByte(self.getPosixSupportHandle(), self.getPos()); self.setPos(self.getPos() + 1); return res & 0xFF; } catch (PosixException e) { @@ -730,7 +721,6 @@ static PBytes read(VirtualFrame frame, PMMap self, Object n, @Bind PythonContext context, @Cached InlinedConditionProfile noneProfile, @Cached InlinedConditionProfile emptyProfile, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PyIndexCheckNode indexCheckNode, @Cached PyNumberAsSizeNode asSizeNode, @Cached InlinedConditionProfile negativeProfile, @@ -757,7 +747,7 @@ static PBytes read(VirtualFrame frame, PMMap self, Object n, return PFactory.createEmptyBytes(context.getLanguage(inliningTarget)); } try { - byte[] buffer = MMapBuiltins.readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), self.getPos(), PythonUtils.toIntExact(nread), constructAndRaiseNode); + byte[] buffer = MMapBuiltins.readBytes(frame, inliningTarget, self, context.getPosixSupport(), self.getPos(), PythonUtils.toIntExact(nread), constructAndRaiseNode); self.setPos(self.getPos() + buffer.length); return PFactory.createBytes(context.getLanguage(inliningTarget), buffer); } catch (OverflowException e) { @@ -775,7 +765,6 @@ abstract static class ReadlineNode extends PythonUnaryBuiltinNode { static Object readline(VirtualFrame frame, PMMap self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SequenceStorageNodes.AppendNode appendNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // Posix abstraction is leaking here a bit: with read mmapped memory, we'd just read @@ -786,7 +775,7 @@ static Object readline(VirtualFrame frame, PMMap self, int nread; outer: while (self.getPos() < self.getLength()) { try { - nread = posixLib.mmapReadBytes(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos(), buffer, (int) Math.min(self.getRemaining(), buffer.length)); + nread = context.getPosixSupport().mmapReadBytes(self.getPosixSupportHandle(), self.getPos(), buffer, (int) Math.min(self.getRemaining(), buffer.length)); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -820,7 +809,6 @@ static int doIt(VirtualFrame frame, PMMap self, Object dataBuffer, @Bind PythonContext context, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("dataBuffer") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { @@ -832,7 +820,7 @@ static int doIt(VirtualFrame frame, PMMap self, Object dataBuffer, if (self.getPos() > self.getLength() || self.getLength() - self.getPos() < dataLen) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.DATA_OUT_OF_RANGE); } - posixLib.mmapWriteBytes(context.getPosixSupport(), self.getPosixSupportHandle(), self.getPos(), dataBytes, dataLen); + context.getPosixSupport().mmapWriteBytes(self.getPosixSupportHandle(), self.getPos(), dataBytes, dataLen); self.setPos(self.getPos() + dataLen); return dataLen; } catch (PosixException e) { @@ -909,7 +897,6 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI @CachedLibrary("subBuffer") PythonBufferAccessLibrary bufferLib, @Cached LongIndexConverterNode startConverter, @Cached LongIndexConverterNode endConverter, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { @@ -930,7 +917,7 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI byte[] firstBuffer = new byte[bufferSize]; byte[] secondBuffer = new byte[bufferSize]; - readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), start, secondBuffer, constructAndRaiseNode, raiseNode); + readBytes(frame, inliningTarget, self, context.getPosixSupport(), start, secondBuffer, constructAndRaiseNode, raiseNode); for (long selfIdx = start; selfIdx <= end - subLen; selfIdx++, buffersIndex++) { // Make sure that the buffers have enough room for the search if (buffersIndex + subLen > bufferSize * 2) { @@ -939,7 +926,7 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI secondBuffer = tmp; buffersIndex -= bufferSize; // move to the tail of the first buffer now long readIndex = selfIdx + subLen - 1; - readBytes(frame, inliningTarget, self, posixLib, context.getPosixSupport(), readIndex, secondBuffer, constructAndRaiseNode, raiseNode); + readBytes(frame, inliningTarget, self, context.getPosixSupport(), readIndex, secondBuffer, constructAndRaiseNode, raiseNode); // It's OK if we read less than buffer size, the outer loop condition // 'selfIdx <= end' and the check in readBytes should cover that we don't // read @@ -969,12 +956,12 @@ static long find(VirtualFrame frame, PMMap self, Object subBuffer, Object startI } } - private static void readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupportLibrary posixLib, PosixSupport posixSupport, long index, byte[] buffer, + private static void readBytes(VirtualFrame frame, Node inliningTarget, PMMap self, PosixSupport posixSupport, long index, byte[] buffer, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PRaiseNode raiseNode) { try { long remaining = self.getLength() - index; int toReadLen = remaining > buffer.length ? buffer.length : (int) remaining; - int nread = posixLib.mmapReadBytes(posixSupport, self.getPosixSupportHandle(), index, buffer, toReadLen); + int nread = posixSupport.mmapReadBytes(self.getPosixSupportHandle(), index, buffer, toReadLen); if (toReadLen != nread) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.SystemError, MMAP_CHANGED_LENGTH); } @@ -1015,7 +1002,6 @@ static Object flush(VirtualFrame frame, PMMap self, long offset, Object sizeObj, @Bind Node inliningTarget, @Bind PythonContext context, @Cached LongIndexConverterNode sizeConversion, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { long size; @@ -1033,7 +1019,7 @@ static Object flush(VirtualFrame frame, PMMap self, long offset, Object sizeObj, } try { - posixLib.mmapFlush(context.getPosixSupport(), self.getPosixSupportHandle(), offset, self.getLength()); + context.getPosixSupport().mmapFlush(self.getPosixSupportHandle(), offset, self.getLength()); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1061,8 +1047,6 @@ public void execute(PythonContext context, Access access) { } private static class ReleaserRootNode extends RootNode { - @Child private PosixSupportLibrary posixSupportLibrary = PosixSupportLibrary.getFactory().createDispatched(1); - ReleaserRootNode(TruffleLanguage language) { super(language); } @@ -1070,7 +1054,7 @@ private static class ReleaserRootNode extends RootNode { @Override public Object execute(VirtualFrame frame) { PMMap.MMapRef ref = (PMMap.MMapRef) frame.getArguments()[0]; - ref.close(posixSupportLibrary, PythonContext.get(this).getPosixSupport()); + ref.close(PythonContext.get(this).getPosixSupport()); return null; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java index bac81eca36..fa45827226 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/PMMap.java @@ -49,14 +49,13 @@ import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode; import com.oracle.graal.python.runtime.AsyncHandler; import com.oracle.graal.python.runtime.NativePosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Exclusive; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; @@ -85,8 +84,8 @@ public Object getPosixSupportHandle() { return ref.getReference(); } - void close(PosixSupportLibrary lib, Object posix) { - ref.close(lib, posix); + void close(PosixSupport posix) { + ref.close(posix); } boolean isClosed() { @@ -146,10 +145,9 @@ int getBufferLength( @ExportMessage byte readByte(int byteOffset, @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Shared("raiseNode") @Cached PConstructAndRaiseNode.Lazy raiseNode) { try { - return posixLib.mmapReadByte(PythonContext.get(raiseNode).getPosixSupport(), getPosixSupportHandle(), byteOffset); + return PythonContext.get(inliningTarget).getPosixSupport().mmapReadByte(getPosixSupportHandle(), byteOffset); } catch (PosixException e) { throw raiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -158,10 +156,9 @@ byte readByte(int byteOffset, @ExportMessage void writeByte(int byteOffset, byte value, @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Shared("raiseNode") @Cached PConstructAndRaiseNode.Lazy raiseNode) { try { - posixLib.mmapWriteByte(PythonContext.get(raiseNode).getPosixSupport(), getPosixSupportHandle(), byteOffset, value); + PythonContext.get(inliningTarget).getPosixSupport().mmapWriteByte(getPosixSupportHandle(), byteOffset, value); } catch (PosixException e) { throw raiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); } @@ -196,7 +193,7 @@ public AsyncHandler.AsyncAction release() { return new MMapBuiltins.ReleaseCallback(this); } - void close(PosixSupportLibrary posixLib, Object posixSupport) { + void close(PosixSupport posixSupport) { if (!markReleased()) { return; } @@ -204,13 +201,13 @@ void close(PosixSupportLibrary posixLib, Object posixSupport) { Object handle = getReference(); if (fd != -1) { try { - posixLib.close(posixSupport, fd); + posixSupport.close(fd); } catch (PosixException e) { // ignored (CPython does not check the return value) } } try { - posixLib.mmapUnmap(posixSupport, handle, length); + posixSupport.mmapUnmap(handle, length); } catch (PosixException e) { // ignored (CPython does not check the return value) } @@ -224,12 +221,10 @@ boolean isNative( } @ExportMessage - long getNativePointer( - @Bind Node inliningTarget, - @Shared @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { + long getNativePointer(@Bind Node inliningTarget) { try { - return posixLib.mmapGetPointer(PythonContext.get(inliningTarget).getPosixSupport(), getPosixSupportHandle()); - } catch (PosixSupportLibrary.UnsupportedPosixFeatureException e) { + return PythonContext.get(inliningTarget).getPosixSupport().mmapGetPointer(getPosixSupportHandle()); + } catch (PosixSupport.UnsupportedPosixFeatureException e) { return NULLPTR; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java index cdc8d373fa..d6fc757b50 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/namespace/SimpleNamespaceBuiltins.java @@ -110,6 +110,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.strings.TruffleString; @@ -180,6 +181,7 @@ static Object init(VirtualFrame frame, PSimpleNamespace self, Object[] args, PKe for (PKeyword keyword : kwargs) { writeAttrNode.execute(self, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwargs.length); return PNone.NONE; } } @@ -248,8 +250,9 @@ static Object replace(VirtualFrame frame, PSimpleNamespace self, @SuppressWarnin if (!(resultObject instanceof PSimpleNamespace result)) { throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.SIMPLE_NAMESPACE_REPLACE_WRONG_TYPE, self, resultObject); } - for (Object key : getKeyArrayNode.execute(self)) { - if (key instanceof TruffleString name) { + Object[] keys = getKeyArrayNode.execute(self); + for (int i = 0; i < keys.length; i++) { + if (keys[i] instanceof TruffleString name) { Object value = readAttrNode.execute(inliningTarget, self, name, PNone.NO_VALUE); if (value != PNone.NO_VALUE) { writeAttrNode.execute(result, name, value); @@ -259,6 +262,7 @@ static Object replace(VirtualFrame frame, PSimpleNamespace self, @SuppressWarnin for (PKeyword change : changes) { writeAttrNode.execute(result, change.getName(), change.getValue()); } + LoopNode.reportLoopCount(inliningTarget, (int) Math.min(Integer.MAX_VALUE, (long) keys.length + changes.length)); return result; } } @@ -296,6 +300,7 @@ public void appendToTruffleStringBuilder(TruffleStringBuilderUTF32 sb, TruffleSt appendStringNode.execute(sb, T_EQ); appendStringNode.execute(sb, item.getRight()); } + LoopNode.reportLoopCount(appendStringNode, items.size()); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java index fb01ce9774..eb488a5cbb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectNodes.java @@ -161,6 +161,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -582,6 +583,7 @@ static Object getstate(VirtualFrame frame, Node inliningTarget, Object obj, bool haveSlots = true; } } + LoopNode.reportLoopCount(inliningTarget, slotnames.length); if (haveSlots) { /* * If we found some slot attributes, pack them in a tuple along the original @@ -705,6 +707,7 @@ static Object reduceNewObj(VirtualFrame frame, Node inliningTarget, Object obj, for (int i = 0; i < argsLen; i++) { newargsVals[i + 1] = getItemNode.execute(frame, inliningTarget, args, i); } + LoopNode.reportLoopCount(inliningTarget, argsLen); } else { newargsVals = new Object[]{cls}; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java index 5dc13a4b3a..98eb90a514 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ordereddict/OrderedDictBuiltins.java @@ -132,6 +132,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -356,6 +357,7 @@ static void update(VirtualFrame frame, Node inliningTarget, Object self, Object throw raiseNode.raise(inliningTarget, RuntimeError, ErrorMessages.MUTATED_DURING_UPDATE, "dict"); } } + LoopNode.reportLoopCount(inliningTarget, initialSize); } else { Object keysAttribute = lookupKeys.execute(frame, inliningTarget, mapping, T_KEYS); if (keysAttribute != PNone.NO_VALUE) { @@ -368,6 +370,7 @@ static void update(VirtualFrame frame, Node inliningTarget, Object self, Object for (PKeyword keyword : kwargs) { setItem.execute(frame, inliningTarget, self, keyword.getName(), keyword.getValue()); } + LoopNode.reportLoopCount(inliningTarget, kwargs.length); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java index 1560852b83..705fb4c983 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/DirEntryBuiltins.java @@ -40,7 +40,6 @@ */ package com.oracle.graal.python.builtins.objects.posix; -import static com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.opaquePathToBytes; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CLASS_GETITEM__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___FSPATH__; import static com.oracle.graal.python.runtime.PosixConstants.AT_FDCWD; @@ -67,12 +66,14 @@ import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins; import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PosixFd; import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PosixPath; +import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.OpaquePathToBytesNode; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.lib.PyObjectReprAsTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; @@ -80,8 +81,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.dsl.Bind; @@ -94,7 +94,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -116,14 +115,15 @@ abstract static class NameNode extends PythonUnaryBuiltinNode { static Object nameAsBytes(VirtualFrame frame, PDirEntry self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile produceBytesProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - return opaquePathToBytes(posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData), posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)); + return opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData), context.getLanguage(inliningTarget)); } else { - return posixLib.getPathAsString(context.getPosixSupport(), posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData)); + return getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), context.getPosixSupport().dirEntryGetName(self.dirEntryData)); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -158,24 +158,25 @@ static PosixPath cached(PDirEntry self) { @Specialization(guards = "self.pathCache == null") static PosixPath createBytes(VirtualFrame frame, Node inliningTarget, PDirEntry self, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile produceBytesProfile, @Cached InlinedConditionProfile posixPathProfile, + @Cached OpaquePathToBytesNode opaquePathToBytesNode, + @Cached PosixSupportNodes.GetPathAsStringNode getPathAsStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Object opaquePath; try { if (posixPathProfile.profile(inliningTarget, self.scandirPath instanceof PosixPath)) { - opaquePath = posixLib.dirEntryGetPath(context.getPosixSupport(), self.dirEntryData, ((PosixPath) self.scandirPath).value); + opaquePath = context.getPosixSupport().dirEntryGetPath(self.dirEntryData, ((PosixPath) self.scandirPath).value); } else { - opaquePath = posixLib.dirEntryGetName(context.getPosixSupport(), self.dirEntryData); + opaquePath = context.getPosixSupport().dirEntryGetName(self.dirEntryData); } } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } if (produceBytesProfile.profile(inliningTarget, self.produceBytes())) { - self.pathCache = new PosixPath(opaquePathToBytes(opaquePath, posixLib, context.getPosixSupport(), context.getLanguage(inliningTarget)), opaquePath, true); + self.pathCache = new PosixPath(opaquePathToBytesNode.execute(inliningTarget, context.getPosixSupport(), opaquePath, context.getLanguage(inliningTarget)), opaquePath, true); } else { - self.pathCache = new PosixPath(posixLib.getPathAsString(context.getPosixSupport(), opaquePath), opaquePath, false); + self.pathCache = new PosixPath(getPathAsStringNode.execute(inliningTarget, context.getPosixSupport(), opaquePath), opaquePath, false); } return self.pathCache; } @@ -208,10 +209,9 @@ abstract static class InodeNode extends PythonUnaryBuiltinNode { @Specialization long inode(VirtualFrame frame, PDirEntry self, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - return posixLib.dirEntryGetInode(getPosixSupport(), self.dirEntryData); + return getPosixSupport().dirEntryGetInode(self.dirEntryData); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -257,7 +257,6 @@ static PTuple cachedLStat(PDirEntry self, boolean followSymlinks, boolean catchN static PTuple uncachedStatWithSymlink(VirtualFrame frame, PDirEntry self, boolean followSymlinks, boolean catchNoent, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @SuppressWarnings("unused") @Cached IsSymlinkNode isSymlinkNode, @SuppressWarnings("unused") @Bind("isSymlinkNode.executeBoolean(frame, self)") boolean isSymlink, @Shared("cachedPosixPathNode") @Cached CachedPosixPathNode cachedPosixPathNode, @@ -265,14 +264,13 @@ static PTuple uncachedStatWithSymlink(VirtualFrame frame, PDirEntry self, boolea @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // There are two caches - one for `follow_symlinks=True` and the other for // 'follow_symlinks=False`. They are different only when the dir entry is a symlink. - return uncachedLStatWithSymlink(frame, self, followSymlinks, catchNoent, inliningTarget, context, posixLib, cachedPosixPathNode, positiveLongProfile, constructAndRaiseNode); + return uncachedLStatWithSymlink(frame, self, followSymlinks, catchNoent, inliningTarget, context, cachedPosixPathNode, positiveLongProfile, constructAndRaiseNode); } @Specialization(guards = {"!followSymlinks", "self.lstatCache == null"}) static PTuple uncachedLStatWithSymlink(VirtualFrame frame, PDirEntry self, boolean followSymlinks, boolean catchNoent, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared("cachedPosixPathNode") @Cached CachedPosixPathNode cachedPosixPathNode, @Shared("positiveLongProfile") @Cached InlinedConditionProfile positiveLongProfile, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -280,7 +278,7 @@ static PTuple uncachedLStatWithSymlink(VirtualFrame frame, PDirEntry self, boole int dirFd = self.scandirPath instanceof PosixFd ? ((PosixFd) self.scandirPath).fd : AT_FDCWD.value; PosixPath posixPath = cachedPosixPathNode.execute(frame, inliningTarget, self); try { - long[] rawStat = posixLib.fstatat(context.getPosixSupport(), dirFd, posixPath.value, followSymlinks); + long[] rawStat = context.getPosixSupport().fstatat(dirFd, posixPath.value, followSymlinks); res = PosixModuleBuiltins.createStatResult(inliningTarget, context.getLanguage(inliningTarget), positiveLongProfile, rawStat); } catch (PosixException e) { if (catchNoent && e.hasErrno(OSErrorEnum.ENOENT)) { @@ -345,9 +343,8 @@ boolean testModeUsingStat(VirtualFrame frame, PDirEntry self, boolean followSyml boolean useTypeIfKnown(VirtualFrame frame, PDirEntry self, @SuppressWarnings("unused") boolean followSymlinks, @Bind Node inliningTarget, @Shared @Cached StatHelperNode statHelperNode, - @Shared @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib) { - int entryType = posixLib.dirEntryGetType(PosixSupport.get(this), self.dirEntryData); + @Shared @Cached SequenceStorageNodes.GetItemScalarNode getItemScalarNode) { + int entryType = PosixSupport.get(this).dirEntryGetType(self.dirEntryData); if (entryType != DT_UNKNOWN.value) { return entryType == expectedDirEntryType; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java index fbe75c77dc..6933af7dfd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/PScandirIterator.java @@ -45,8 +45,8 @@ import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject; import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.AsyncHandler.SharedFinalizer; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.truffle.api.object.Shape; @@ -75,16 +75,16 @@ public AsyncAction release() { return new ScandirIteratorBuiltins.ReleaseCallback(this); } - void rewindAndClose(PosixSupportLibrary posixLib, Object posixSupport) { + void rewindAndClose(PosixSupport posixSupport) { if (!markReleased()) { return; } Object dirStream = getReference(); if (needsRewind) { - posixLib.rewinddir(posixSupport, dirStream); + posixSupport.rewinddir(dirStream); } try { - posixLib.closedir(posixSupport, dirStream); + posixSupport.closedir(dirStream); } catch (PosixException e) { // ignored (CPython does not chek the return value of closedir) } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java index 6e5b03fee1..e4f7e136db 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/posix/ScandirIteratorBuiltins.java @@ -61,8 +61,7 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.runtime.AsyncHandler.AsyncAction; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.ThreadLocalAction.Access; @@ -73,7 +72,6 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; @@ -91,9 +89,8 @@ protected List> getNodeFa @GenerateNodeFactory abstract static class CloseNode extends PythonUnaryBuiltinNode { @Specialization - PNone close(PScandirIterator self, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - self.ref.rewindAndClose(posixLib, getPosixSupport()); + PNone close(PScandirIterator self) { + self.ref.rewindAndClose(getPosixSupport()); return PNone.NONE; } } @@ -113,7 +110,6 @@ abstract static class NextNode extends TpIterNextBuiltin { @Specialization static Object next(VirtualFrame frame, PScandirIterator self, @Bind Node inliningTarget, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Bind PythonLanguage language) { if (self.ref.isReleased()) { @@ -121,14 +117,14 @@ static Object next(VirtualFrame frame, PScandirIterator self, } PosixSupport posixSupport = PosixSupport.get(inliningTarget); try { - Object dirEntryData = posixLib.readdir(posixSupport, self.ref.getReference()); + Object dirEntryData = posixSupport.readdir(self.ref.getReference()); if (dirEntryData == null) { - self.ref.rewindAndClose(posixLib, posixSupport); + self.ref.rewindAndClose(posixSupport); throw iteratorExhausted(); } return PFactory.createDirEntry(language, dirEntryData, self.path); } catch (PosixException e) { - self.ref.rewindAndClose(posixLib, posixSupport); + self.ref.rewindAndClose(posixSupport); throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -148,9 +144,8 @@ PScandirIterator iter(PScandirIterator self) { abstract static class ExitNode extends PythonBuiltinNode { @Specialization @SuppressWarnings("unused") - PNone exit(PScandirIterator self, Object type, Object value, Object traceback, - @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib) { - self.ref.rewindAndClose(posixLib, getPosixSupport()); + PNone exit(PScandirIterator self, Object type, Object value, Object traceback) { + self.ref.rewindAndClose(getPosixSupport()); return PNone.NONE; } } @@ -174,8 +169,6 @@ public void execute(PythonContext context, Access access) { } private static class ReleaserRootNode extends RootNode { - @Child private PosixSupportLibrary posixSupportLibrary = PosixSupportLibrary.getFactory().createDispatched(1); - ReleaserRootNode(TruffleLanguage language) { super(language); } @@ -183,7 +176,7 @@ private static class ReleaserRootNode extends RootNode { @Override public Object execute(VirtualFrame frame) { PScandirIterator.DirStreamRef ref = (PScandirIterator.DirStreamRef) frame.getArguments()[0]; - ref.rewindAndClose(posixSupportLibrary, PythonContext.get(this).getPosixSupport()); + ref.rewindAndClose(PythonContext.get(this).getPosixSupport()); return null; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java index ab11fb3522..e0c75dd82f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/range/RangeBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2014, Regents of the University of California * * All rights reserved. @@ -118,6 +118,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -1058,6 +1059,7 @@ static Object containsIterator(VirtualFrame frame, PIntRange self, Object elem, break; } if (eqNode.executeEq(frame, inliningTarget, elem, item)) { + LoopNode.reportLoopCount(inliningTarget, idx); return idx; } if (idx == SysModuleBuiltins.MAXSIZE) { @@ -1065,6 +1067,7 @@ static Object containsIterator(VirtualFrame frame, PIntRange self, Object elem, } idx++; } + LoopNode.reportLoopCount(inliningTarget, idx); throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.D_IS_NOT_IN_RANGE, elem); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java index eb2dc10cd0..97bec5dc30 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/select/PollBuiltins.java @@ -72,8 +72,7 @@ import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -85,7 +84,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @CoreFunctions(extendClasses = PythonBuiltinClassType.PPoll) @@ -157,7 +156,6 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, @Bind PythonLanguage language, @Cached PyTimeFromObjectNode fromTime, @Cached IsBuiltinObjectProfile typeErrorProfile, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -192,7 +190,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, try { gil.release(true); try { - posixLib.poll(PosixSupport.get(inliningTarget), pollFds, pollEvents, pollRevents, timeoutMs); + PosixSupport.get(inliningTarget).poll(pollFds, pollEvents, pollRevents, timeoutMs); } finally { gil.acquire(); } @@ -226,6 +224,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, resultSize++; } } + LoopNode.reportLoopCount(inliningTarget, pollRevents.length); Object[] result = new Object[resultSize]; int resultIndex = 0; for (int i = 0; i < pollRevents.length; i++) { @@ -233,6 +232,7 @@ static PList poll(VirtualFrame frame, PPoll self, Object timeoutObject, result[resultIndex++] = PFactory.createTuple(language, new Object[]{pollFds[i], pollRevents[i]}); } } + LoopNode.reportLoopCount(inliningTarget, pollRevents.length); return PFactory.createList(language, result); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java index b183fda862..cd6bb91da5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/BaseSetBuiltins.java @@ -107,6 +107,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -233,6 +234,7 @@ static Object reduce(VirtualFrame frame, PBaseSet self, assert hasNext; keysArray[i] = getIterKey.execute(inliningTarget, storage, it); } + LoopNode.reportLoopCount(inliningTarget, len); PTuple contents = PFactory.createTuple(language, new Object[]{PFactory.createList(language, keysArray)}); Object state = getStateNode.execute(frame, inliningTarget, self); return PFactory.createTuple(language, new Object[]{getClassNode.execute(inliningTarget, self), contents, state}); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java index d1b18929bf..4b19dc96e9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/FrozenSetBuiltins.java @@ -74,6 +74,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; /** @@ -179,6 +180,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PFrozenSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = intersectNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } @@ -258,6 +260,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PFrozenSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = diffNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } @@ -306,6 +309,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PBaseSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = addAllToOther.execute(frame, inliningTarget, getHashingStorage.execute(frame, inliningTarget, args[i]), result); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createFrozenSet(language, result); } } @@ -343,6 +347,7 @@ public static long computeHash(VirtualFrame frame, PFrozenSet self, long tmp = hashNode.execute(frame, inliningTarget, key); hash ^= shuffleBits(tmp); } + LoopNode.reportLoopCount(inliningTarget, len); // TODO: // Remove the effect of an odd number of NULL entries diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java index b97df64f4a..211a083064 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetBuiltins.java @@ -99,6 +99,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -260,6 +261,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = addAllToOther.execute(frame, inliningTarget, getSetStorageNode.execute(frame, inliningTarget, args[i]), result); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createSet(language, result); } } @@ -315,6 +317,7 @@ static void updateMappingproxy(VirtualFrame frame, PHashingCollection collection Object key = storageIterKey.execute(inliningTarget, source, iterator); curStorage = setStorageItem.execute(frame, inliningTarget, curStorage, key, PNone.NONE); } + LoopNode.reportLoopCount(inliningTarget, size); collection.setDictStorage(curStorage); } @@ -337,6 +340,7 @@ static void doBuiltin(VirtualFrame frame, PHashingCollection collection, @Suppre Object key = getItemScalarNode.execute(inliningTarget, sequenceStorage, i); curStorage = setStorageItem.execute(frame, inliningTarget, curStorage, key, PNone.NONE); } + LoopNode.reportLoopCount(inliningTarget, length); collection.setDictStorage(curStorage); } @@ -412,6 +416,7 @@ static PNone doSet(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { storage = addAllToOther.execute(frame, inliningTarget, getSetStorageNode.execute(frame, inliningTarget, o), storage); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(storage); return PNone.NONE; } @@ -496,6 +501,7 @@ Object doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = intersectNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return createResult(self, result); } @@ -608,6 +614,7 @@ static PNone doSetArgs(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { result = xorNode.executeMutatingLeft(frame, inliningTarget, result, getHashingStorage.execute(frame, inliningTarget, o)); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(result); return PNone.NONE; } @@ -682,6 +689,7 @@ static PBaseSet doGeneric(VirtualFrame frame, PSet self, Object[] args, for (int i = 0; i < args.length; i++) { result = diffNode.execute(frame, inliningTarget, result, getSetStorageNode.execute(frame, inliningTarget, args[i])); } + LoopNode.reportLoopCount(inliningTarget, args.length); return PFactory.createSet(language, result); } @@ -733,6 +741,7 @@ static PNone doSet(VirtualFrame frame, PSet self, Object[] args, for (Object o : args) { result = diffNode.execute(frame, inliningTarget, result, getHashingStorage.execute(frame, inliningTarget, o)); } + LoopNode.reportLoopCount(inliningTarget, args.length); self.setDictStorage(result); return PNone.NONE; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index e80d199a7b..30a2474890 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -97,12 +97,10 @@ import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; import com.oracle.graal.python.runtime.PosixSupport; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.RecvfromResult; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -172,7 +170,6 @@ public abstract static class InitNode extends PythonClinicBuiltinNode { @Specialization static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, int protoIn, @SuppressWarnings("unused") PNone fileno, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -196,18 +193,18 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i int fd; gil.release(true); try { - fd = posixLib.socket(context.getPosixSupport(), family, type, proto); + fd = context.getPosixSupport().socket(family, type, proto); } finally { gil.acquire(); } try { - posixLib.setInheritable(context.getPosixSupport(), fd, false); - sockInit(context, posixLib, self, fd, family, type, proto); + context.getPosixSupport().setInheritable(fd, false); + sockInit(context, self, fd, family, type, proto); } catch (Exception e) { // If we failed before giving the fd to python-land, close it CompilerDirectives.transferToInterpreterAndInvalidate(); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } catch (PosixException posixException) { // ignore } @@ -222,8 +219,6 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i @Specialization(guards = "!isPNone(fileno)") static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, int protoIn, Object fileno, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") UniversalSockAddrLibrary addrLib, @Bind Node inliningTarget, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PyLongAsIntNode asIntNode, @@ -238,9 +233,9 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i } int family = familyIn; try { - UniversalSockAddr addr = posixLib.getsockname(context.getPosixSupport(), fd); + UniversalSockAddr addr = context.getPosixSupport().getsockname(fd); if (family == -1) { - family = addrLib.getFamily(addr); + family = addr.getFamily(); } } catch (PosixException e) { if (family == -1 || e.hasErrno(EBADF) || e.hasErrno(ENOTSOCK)) { @@ -250,24 +245,24 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i try { int type = typeIn; if (type == -1) { - type = getIntSockopt(context.getPosixSupport(), posixLib, fd, SOL_SOCKET.value, SO_TYPE.value); + type = getIntSockopt(context.getPosixSupport(), fd, SOL_SOCKET.value, SO_TYPE.value); } int proto = protoIn; if (SO_PROTOCOL.defined) { if (proto == -1) { - proto = getIntSockopt(context.getPosixSupport(), posixLib, fd, SOL_SOCKET.value, SO_PROTOCOL.getValueIfDefined()); + proto = getIntSockopt(context.getPosixSupport(), fd, SOL_SOCKET.value, SO_PROTOCOL.getValueIfDefined()); } } else { proto = 0; } - sockInit(context, posixLib, self, fd, family, type, proto); + sockInit(context, self, fd, family, type, proto); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; } - private static void sockInit(PythonContext context, PosixSupportLibrary posixLib, + private static void sockInit(PythonContext context, PSocket self, int fd, int family, int type, int proto) throws PosixException { self.setFd(fd); self.setFamily(family); @@ -277,13 +272,13 @@ private static void sockInit(PythonContext context, PosixSupportLibrary posixLib long defaultTimeout = context.lookupBuiltinModule(T__SOCKET).getModuleState(Long.class); self.setTimeoutNs(defaultTimeout); if (defaultTimeout >= 0) { - posixLib.setBlocking(context.getPosixSupport(), fd, false); + context.getPosixSupport().setBlocking(fd, false); } } - private static int getIntSockopt(PosixSupport posixSupport, PosixSupportLibrary posixLib, int fd, int level, int option) throws PosixException { + private static int getIntSockopt(PosixSupport posixSupport, int fd, int level, int option) throws PosixException { byte[] tmp = new byte[4]; - int len = posixLib.getsockopt(posixSupport, fd, level, option, tmp, tmp.length); + int len = posixSupport.getsockopt(fd, level, option, tmp, tmp.length); assert len == tmp.length; return PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); } @@ -312,7 +307,6 @@ abstract static class AcceptNode extends PythonUnaryBuiltinNode { static Object accept(VirtualFrame frame, PSocket self, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -321,18 +315,18 @@ static Object accept(VirtualFrame frame, PSocket self, try { PosixSupport posixSupport = context.getPosixSupport(); - PosixSupportLibrary.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, self, - (p, s) -> p.accept(s, self.getFd()), + PosixSupport.AcceptResult acceptResult = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, + s -> s.accept(self.getFd()), false, false); try { Object pythonAddr = makeSockAddrNode.execute(frame, inliningTarget, acceptResult.sockAddr); - posixLib.setInheritable(posixSupport, acceptResult.socketFd, false); + posixSupport.setInheritable(acceptResult.socketFd, false); return PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{acceptResult.socketFd, pythonAddr}); } catch (Exception e) { // If we failed before giving the fd to python-land, close it CompilerDirectives.transferToInterpreterAndInvalidate(); try { - posixLib.close(posixSupport, acceptResult.socketFd); + posixSupport.close(acceptResult.socketFd); } catch (PosixException posixException) { // ignore } @@ -352,7 +346,6 @@ abstract static class BindNode extends PythonBinaryBuiltinNode { static Object bind(VirtualFrame frame, PSocket self, Object address, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLibrary, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @@ -363,7 +356,7 @@ static Object bind(VirtualFrame frame, PSocket self, Object address, try { gil.release(true); try { - posixLibrary.bind(context.getPosixSupport(), self.getFd(), addr); + context.getPosixSupport().bind(self.getFd(), addr); } finally { gil.acquire(); } @@ -382,7 +375,6 @@ abstract static class CloseNode extends PythonUnaryBuiltinNode { static Object close(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int fd = socket.getFd(); @@ -391,7 +383,7 @@ static Object close(VirtualFrame frame, PSocket socket, socket.setFd(INVALID_FD); gil.release(true); try { - posixLib.close(context.getPosixSupport(), fd); + context.getPosixSupport().close(fd); } finally { gil.acquire(); } @@ -413,7 +405,6 @@ abstract static class ConnectNode extends PythonBinaryBuiltinNode { @Specialization static Object connect(VirtualFrame frame, PSocket self, Object address, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached GilNode gil, @@ -424,19 +415,19 @@ static Object connect(VirtualFrame frame, PSocket self, Object address, auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); try { - doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); + doConnect(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, self, connectAddr); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } return PNone.NONE; } - static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, PSocket self, + static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket self, UniversalSockAddr connectAddr) throws PosixException { try { gil.release(true); try { - posixLib.connect(posixSupport, self.getFd(), connectAddr); + posixSupport.connect(self.getFd(), connectAddr); } finally { gil.acquire(); } @@ -449,13 +440,13 @@ static void doConnect(Frame frame, Node inliningTarget, PConstructAndRaiseNode.L waitConnect = self.getTimeoutNs() > 0 && e.hasErrno(EINPROGRESS) && isSelectable(self); } if (waitConnect) { - SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, self, - (p, s) -> { + SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, self, + s -> { byte[] tmp = new byte[4]; - p.getsockopt(s, self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); + s.getsockopt(self.getFd(), SOL_SOCKET.value, SO_ERROR.value, tmp, tmp.length); int err = PythonUtils.ARRAY_ACCESSOR.getInt(tmp, 0); if (err != 0 && err != EISCONN.getNumber()) { - throw new PosixErrnoException(err, p.strerror(s, err)); + throw new PosixErrnoException(err, s.strerror(err)); } return null; }, @@ -474,7 +465,6 @@ abstract static class ConnectExNode extends PythonBinaryBuiltinNode { @Specialization static Object connectEx(VirtualFrame frame, PSocket self, Object address, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @Cached GilNode gil, @@ -485,7 +475,7 @@ static Object connectEx(VirtualFrame frame, PSocket self, Object address, auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); // sic! connect try { - ConnectNode.doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); + ConnectNode.doConnect(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, self, connectAddr); } catch (PosixException e) { if (e instanceof PosixErrnoException errnoException) { return errnoException.getErrorCode(); @@ -504,7 +494,6 @@ abstract static class GetPeerNameNode extends PythonUnaryBuiltinNode { static Object get(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -512,7 +501,7 @@ static Object get(VirtualFrame frame, PSocket socket, UniversalSockAddr addr; gil.release(true); try { - addr = posixLib.getpeername(context.getPosixSupport(), socket.getFd()); + addr = context.getPosixSupport().getpeername(socket.getFd()); } finally { gil.acquire(); } @@ -531,7 +520,6 @@ abstract static class GetSockNameNode extends PythonUnaryBuiltinNode { static Object get(VirtualFrame frame, PSocket socket, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { @@ -539,7 +527,7 @@ static Object get(VirtualFrame frame, PSocket socket, UniversalSockAddr addr; gil.release(true); try { - addr = posixLib.getsockname(context.getPosixSupport(), socket.getFd()); + addr = context.getPosixSupport().getsockname(socket.getFd()); } finally { gil.acquire(); } @@ -583,7 +571,6 @@ abstract static class ListenNode extends PythonBinaryClinicBuiltinNode { static Object listen(VirtualFrame frame, PSocket self, int backlogIn, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { int backlog = backlogIn; @@ -593,7 +580,7 @@ static Object listen(VirtualFrame frame, PSocket self, int backlogIn, try { gil.release(true); try { - posixLib.listen(context.getPosixSupport(), self.getFd(), backlog); + context.getPosixSupport().listen(self.getFd(), backlog); } finally { gil.acquire(); } @@ -619,7 +606,6 @@ abstract static class RecvNode extends PythonTernaryClinicBuiltinNode { static Object recv(VirtualFrame frame, PSocket socket, int recvlen, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -640,8 +626,8 @@ static Object recv(VirtualFrame frame, PSocket socket, int recvlen, int flags, } try { - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recv(s, socket.getFd(), bytes, 0, bytes.length, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recv(socket.getFd(), bytes, 0, bytes.length, flags), false, false); if (outlen == 0) { return PFactory.createEmptyBytes(language); @@ -669,7 +655,6 @@ abstract static class RecvFromNode extends PythonTernaryClinicBuiltinNode { static Object recvFrom(VirtualFrame frame, PSocket socket, int recvlen, int flags, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -687,8 +672,8 @@ static Object recvFrom(VirtualFrame frame, PSocket socket, int recvlen, int flag } try { - RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recvfrom(s, socket.getFd(), bytes, 0, bytes.length, flags), + RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recvfrom(socket.getFd(), bytes, 0, bytes.length, flags), false, false); PBytes resultBytes; PythonLanguage language = context.getLanguage(inliningTarget); @@ -723,7 +708,6 @@ static Object recvInto(VirtualFrame frame, PSocket socket, Object bufferObj, int @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -757,8 +741,8 @@ static Object recvInto(VirtualFrame frame, PSocket socket, Object bufferObj, int final int len = recvlen; try { - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recv(s, socket.getFd(), bytes, 0, len, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recv(socket.getFd(), bytes, 0, len, flags), false, false); if (!directWrite) { bufferLib.writeFromByteArray(buffer, 0, bytes, 0, outlen); @@ -791,7 +775,6 @@ static Object recvFromInto(VirtualFrame frame, PSocket socket, Object bufferObj, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached SocketNodes.MakeSockAddrNode makeSockAddrNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -825,8 +808,8 @@ static Object recvFromInto(VirtualFrame frame, PSocket socket, Object bufferObj, } try { - RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.recvfrom(s, socket.getFd(), bytes, 0, bytes.length, flags), + RecvfromResult result = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.recvfrom(socket.getFd(), bytes, 0, bytes.length, flags), false, false); if (!directWrite) { bufferLib.writeFromByteArray(buffer, 0, bytes, 0, result.readBytes); @@ -858,7 +841,6 @@ static int send(VirtualFrame frame, PSocket socket, Object bufferObj, int flags, @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -870,8 +852,8 @@ static int send(VirtualFrame frame, PSocket socket, Object bufferObj, int flags, byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); try { - return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.send(s, socket.getFd(), bytes, 0, len, flags), + return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.send(socket.getFd(), bytes, 0, len, flags), true, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -899,7 +881,6 @@ static Object sendAll(VirtualFrame frame, PSocket socket, Object bufferObj, int @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { @@ -921,8 +902,8 @@ static Object sendAll(VirtualFrame frame, PSocket socket, Object bufferObj, int try { final int offset1 = offset; final int len1 = len; - int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.send(s, socket.getFd(), bytes, offset1, len1, flags), + int outlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.send(socket.getFd(), bytes, offset1, len1, flags), true, false, timeoutHelper); offset += outlen; len -= outlen; @@ -958,7 +939,6 @@ static Object sendTo(VirtualFrame frame, PSocket socket, Object bufferObj, Objec @Cached("createFor($node)") InteropCallData callData, @CachedLibrary("bufferObj") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached InlinedConditionProfile hasFlagsProfile, @Cached PyLongAsIntNode asIntNode, @Cached SocketNodes.GetSockAddrArgNode getSockAddrArgNode, @@ -987,8 +967,8 @@ static Object sendTo(VirtualFrame frame, PSocket socket, Object bufferObj, Objec byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); try { - return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket, - (p, s) -> p.sendto(s, socket.getFd(), bytes, 0, len, flags, addr), + return SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket, + s -> s.sendto(socket.getFd(), bytes, 0, len, flags, addr), true, false); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); @@ -1007,10 +987,9 @@ public abstract static class SetBlockingNode extends PythonBinaryClinicBuiltinNo static PNone doBoolean(VirtualFrame frame, PSocket socket, boolean blocking, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.setBlocking(context.getPosixSupport(), socket.getFd(), blocking); + context.getPosixSupport().setBlocking(socket.getFd(), blocking); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1032,13 +1011,12 @@ abstract static class SetTimeoutNode extends PythonBinaryBuiltinNode { static Object setTimeout(VirtualFrame frame, PSocket socket, Object seconds, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached SocketNodes.ParseTimeoutNode parseTimeoutNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long timeout = parseTimeoutNode.execute(frame, inliningTarget, seconds); socket.setTimeoutNs(timeout); try { - posixLib.setBlocking(context.getPosixSupport(), socket.getFd(), timeout < 0); + context.getPosixSupport().setBlocking(socket.getFd(), timeout < 0); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1055,10 +1033,9 @@ abstract static class ShutdownNode extends PythonBinaryClinicBuiltinNode { static Object shutdown(VirtualFrame frame, PSocket socket, int how, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { - posixLib.shutdown(context.getPosixSupport(), socket.getFd(), how); + context.getPosixSupport().shutdown(socket.getFd(), how); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1132,7 +1109,6 @@ abstract static class SetSockOptNode extends PythonClinicBuiltinNode { static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, Object value, @SuppressWarnings("unused") PNone none, @Bind PythonContext context, @Cached("createFor($node)") InteropCallData callData, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @CachedLibrary(limit = "3") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "3") PythonBufferAccessLibrary bufferLib, @Bind Node inliningTarget, @@ -1156,7 +1132,7 @@ static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, } try { - posixLib.setsockopt(context.getPosixSupport(), socket.getFd(), level, option, bytes, len); + context.getPosixSupport().setsockopt(socket.getFd(), level, option, bytes, len); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1166,7 +1142,6 @@ static Object setInt(VirtualFrame frame, PSocket socket, int level, int option, @Specialization(guards = "isNone(none)") static Object setNull(VirtualFrame frame, PSocket socket, int level, int option, @SuppressWarnings("unused") PNone none, Object buflenObj, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Bind Node inliningTarget, @Exclusive @Cached PyLongAsIntNode asIntNode, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @@ -1177,7 +1152,7 @@ static Object setNull(VirtualFrame frame, PSocket socket, int level, int option, throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SETSECKOPT_BUFF_OUT_OFRANGE); } try { - posixLib.setsockopt(context.getPosixSupport(), socket.getFd(), level, option, null, buflen); + context.getPosixSupport().setsockopt(socket.getFd(), level, option, null, buflen); } catch (PosixException e) { throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } @@ -1207,17 +1182,16 @@ abstract static class GetSockOptNode extends PythonQuaternaryClinicBuiltinNode { static Object getSockOpt(VirtualFrame frame, PSocket socket, int level, int option, int buflen, @Bind Node inliningTarget, @Bind PythonContext context, - @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { try { if (buflen == 0) { byte[] result = new byte[4]; - posixLib.getsockopt(context.getPosixSupport(), socket.getFd(), level, option, result, result.length); + context.getPosixSupport().getsockopt(socket.getFd(), level, option, result, result.length); return PythonUtils.ARRAY_ACCESSOR.getInt(result, 0); } else if (buflen > 0 && buflen < 1024) { byte[] result = new byte[buflen]; - int len = posixLib.getsockopt(context.getPosixSupport(), socket.getFd(), level, option, result, result.length); + int len = context.getPosixSupport().getsockopt(socket.getFd(), level, option, result, result.length); return PFactory.createBytes(context.getLanguage(inliningTarget), result, len); } else { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.GETSECKOPT_BUFF_OUT_OFRANGE); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java index fe3facd298..6656fab1cd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketNodes.java @@ -82,22 +82,21 @@ import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodes; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.InteropCallData; import com.oracle.graal.python.runtime.PosixConstants; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.AddrInfoCursor; +import com.oracle.graal.python.runtime.PosixSupport.GetAddrInfoException; +import com.oracle.graal.python.runtime.PosixSupport.Inet4SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.Inet6SockAddr; +import com.oracle.graal.python.runtime.PosixSupport.InvalidAddressException; +import com.oracle.graal.python.runtime.PosixSupport.InvalidUnixSocketPathException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UniversalSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnixSockAddr; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.object.PFactory; @@ -112,6 +111,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleString.Encoding; @@ -127,8 +127,6 @@ public abstract static class GetSockAddrArgNode extends Node { @Specialization(guards = "isInet(socket)") static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") @Shared("sockAddrLib") UniversalSockAddrLibrary sockAddrLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -148,15 +146,13 @@ static UniversalSockAddr doInet(VirtualFrame frame, @SuppressWarnings("unused") byte[] host = idnaConverter.execute(frame, tupleGetItem.execute(inliningTarget, address, 0)); int port = parsePort(frame, caller, asIntNode, inliningTarget, errorProfile, tupleGetItem.execute(inliningTarget, address, 1), raiseNode); UniversalSockAddr addr = setIpAddrNode.execute(frame, host, AF_INET.value); - Object posixSupport = context.getPosixSupport(); - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(port, sockAddrLib.asInet4SockAddr(addr).getAddress())); + PosixSupport posixSupport = context.getPosixSupport(); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(port, addr.asInet4SockAddr().getAddress())); } @Specialization(guards = "isInet6(socket)") static UniversalSockAddr doInet6(VirtualFrame frame, @SuppressWarnings("unused") PSocket socket, Object address, String caller, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") @Shared("sockAddrLib") UniversalSockAddrLibrary sockAddrLib, @Shared("tupleCheck") @Cached PyTupleCheckNode tupleCheckNode, @Cached @Shared("tupleSize") PyTupleSizeNode tupleSize, @Cached @Shared("tupleGetItem") PyTupleGetItem tupleGetItem, @@ -187,8 +183,8 @@ static UniversalSockAddr doInet6(VirtualFrame frame, @SuppressWarnings("unused") scopeid = asIntNode.execute(frame, inliningTarget, tupleGetItem.execute(inliningTarget, address, 3)); } UniversalSockAddr addr = setIpAddrNode.execute(frame, host, AF_INET6.value); - Object posixSupport = context.getPosixSupport(); - return posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(port, sockAddrLib.asInet6SockAddr(addr).getAddress(), flowinfo, scopeid)); + PosixSupport posixSupport = context.getPosixSupport(); + return posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(port, addr.asInet6SockAddr().getAddress(), flowinfo, scopeid)); } @Specialization(guards = "isUnix(socket)") @@ -200,7 +196,6 @@ static UniversalSockAddr doUnix(VirtualFrame frame, @SuppressWarnings("unused") @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode, @CachedLibrary(limit = "1") PythonBufferAcquireLibrary bufferAcquireLib, @CachedLibrary(limit = "1") PythonBufferAccessLibrary bufferLib, - @CachedLibrary(limit = "1") @Shared("posixLib") PosixSupportLibrary posixLib, @Exclusive @Cached PRaiseNode raiseNode) { byte[] path; if (unicodeCheckNode.execute(inliningTarget, address)) { @@ -218,9 +213,9 @@ static UniversalSockAddr doUnix(VirtualFrame frame, @SuppressWarnings("unused") path = arrayCopyOf(path, path.length + 1); } PythonContext context = PythonContext.get(inliningTarget); - Object posixSupport = context.getPosixSupport(); + PosixSupport posixSupport = context.getPosixSupport(); try { - return posixLib.createUniversalSockAddrUnix(posixSupport, new UnixSockAddr(path)); + return posixSupport.createUniversalSockAddrUnix(new UnixSockAddr(path)); } catch (UnsupportedPosixFeatureException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.AF_UNIX_NOT_SUPPORTED, caller); } catch (InvalidUnixSocketPathException e) { @@ -277,28 +272,28 @@ public abstract static class SetIpAddrNode extends Node { @Specialization static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @Bind Node inliningTarget, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary(limit = "1") AddrInfoCursorLibrary addrInfoLib, @Cached InetPtoNCachedPNode inetPtoNCachedPNode, + @Cached PosixSupportNodes.CreateCStringFromStringNode createCStringFromStringNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GilNode gil, @Cached PRaiseNode raiseNode) { PythonContext context = PythonContext.get(inliningTarget); - Object posixSupport = context.getPosixSupport(); + PosixSupport posixSupport = context.getPosixSupport(); try { if (name.length == 0) { + Object zero = createCStringFromStringNode.execute(inliningTarget, posixSupport, T_ZERO); gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, null, posixLib.createCStringFromString(posixSupport, T_ZERO), + AddrInfoCursor cursor = posixSupport.getaddrinfo(null, zero, family, SOCK_DGRAM.value, 0, AI_PASSIVE.value); try { - if (addrInfoLib.next(cursor)) { + if (cursor.next()) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.WILD_CARD_RESOLVED_TO_MULTIPLE_ADDRESS); } - return addrInfoLib.getSockAddr(cursor); + return cursor.getSockAddr(); } finally { - addrInfoLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); @@ -309,14 +304,14 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, if (family != AF_INET.value && family != AF_UNSPEC.value) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.ADDRESS_FAMILY_MISMATCHED); } - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(0, INADDR_BROADCAST.value)); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(0, INADDR_BROADCAST.value)); } /* avoid a name resolution in case of numeric address */ /* check for an IPv4 address */ if (family == AF_INET.value || family == AF_UNSPEC.value) { - byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET.value, name); + byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixSupport, AF_INET.value, name); if (bytes != null) { - return posixLib.createUniversalSockAddrInet4(posixSupport, new Inet4SockAddr(0, bytes)); + return posixSupport.createUniversalSockAddrInet4(new Inet4SockAddr(0, bytes)); } } /* @@ -324,22 +319,22 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, * getaddrinfo(), which can handle translation from interface name to interface * index */ - if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(name)) { - byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixLib, posixSupport, AF_INET6.value, name); + if ((family == AF_INET6.value || family == AF_UNSPEC.value) && !hasScopeId(inliningTarget, name)) { + byte[] bytes = inetPtoNCachedPNode.execute(inliningTarget, posixSupport, AF_INET6.value, name); if (bytes != null) { - return posixLib.createUniversalSockAddrInet6(posixSupport, new Inet6SockAddr(0, bytes, 0, 0)); + return posixSupport.createUniversalSockAddrInet6(new Inet6SockAddr(0, bytes, 0, 0)); } } /* perform a name resolution */ gil.release(true); try { // TODO getaddrinfo lock? - AddrInfoCursor cursor = posixLib.getaddrinfo(posixSupport, posixLib.createCStringFromBytes(posixSupport, name), null, + AddrInfoCursor cursor = posixSupport.getaddrinfo(posixSupport.createCStringFromBytes(name), null, family, 0, 0, 0); try { - return addrInfoLib.getSockAddr(cursor); + return cursor.getSockAddr(); } finally { - addrInfoLib.release(cursor); + cursor.release(); } } finally { gil.acquire(); @@ -355,34 +350,36 @@ static UniversalSockAddr setipaddr(VirtualFrame frame, byte[] name, int family, @GenerateCached(false) @ImportStatic(Arrays.class) abstract static class InetPtoNCachedPNode extends Node { - abstract byte[] execute(Node inliningTarget, PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string); + abstract byte[] execute(Node inliningTarget, PosixSupport posixSupport, int family, byte[] string); @Specialization(guards = {"family == cachedFamily", "equals(string, cachedString)"}, limit = "3") @SuppressWarnings("unused") - static byte[] cached(PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string, + static byte[] cached(PosixSupport posixSupport, int family, byte[] string, @Cached("family") int cachedFamily, @Cached(value = "string", dimensions = 1) byte[] cachedString, - @Cached(value = "doParse(posixLib, posixSupport, family, string)", dimensions = 1) byte[] cachedResult) { + @Cached(value = "doParse(posixSupport, family, string)", dimensions = 1) byte[] cachedResult) { return cachedResult; } @Specialization(replaces = "cached") - static byte[] doParse(PosixSupportLibrary posixLib, Object posixSupport, int family, byte[] string) { + static byte[] doParse(PosixSupport posixSupport, int family, byte[] string) { assert family == AF_INET.value || family == AF_INET6.value; try { - return posixLib.inet_pton(posixSupport, family, posixLib.createCStringFromBytes(posixSupport, string)); + return posixSupport.inet_pton(family, posixSupport.createCStringFromBytes(string)); } catch (PosixException | InvalidAddressException e) { return null; } } } - private static boolean hasScopeId(byte[] name) { - for (byte b : name) { - if (b == '%') { + private static boolean hasScopeId(Node inliningTarget, byte[] name) { + for (int i = 0; i < name.length; i++) { + if (name[i] == '%') { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, name.length); return false; } } @@ -395,30 +392,29 @@ private static boolean hasScopeId(byte[] name) { public abstract static class MakeSockAddrNode extends Node { public abstract Object execute(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr); - @Specialization(limit = "1") + @Specialization static Object makeSockAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary("addr") UniversalSockAddrLibrary addrLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.FromByteArrayNode fromByteArrayNode, @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { try { PythonContext context = PythonContext.get(inliningTarget); PythonLanguage language = context.getLanguage(inliningTarget); - int family = addrLib.getFamily(addr); + int family = addr.getFamily(); if (family == AF_INET.value) { - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - TruffleString addressString = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); + PosixSupport posixSupport = context.getPosixSupport(); + TruffleString addressString = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); return PFactory.createTuple(language, new Object[]{addressString, inet4SockAddr.getPort()}); } else if (family == AF_INET6.value) { - Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - TruffleString addressString = posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); + PosixSupport posixSupport = context.getPosixSupport(); + TruffleString addressString = getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); return PFactory.createTuple(language, new Object[]{addressString, inet6SockAddr.getPort(), inet6SockAddr.getFlowInfo(), inet6SockAddr.getScopeId()}); } else if (family == AF_UNIX.value) { - UnixSockAddr unixSockAddr = addrLib.asUnixSockAddr(addr); + UnixSockAddr unixSockAddr = addr.asUnixSockAddr(); byte[] path = unixSockAddr.getPath(); if (PosixConstants.IS_LINUX && path.length > 0 && path[0] == 0) { // linux-specific "abstract" address @@ -455,23 +451,22 @@ private static TruffleString bytesToString(byte[] path, TruffleString.FromByteAr public abstract static class MakeIpAddrNode extends Node { public abstract Object execute(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr); - @Specialization(limit = "1") + @Specialization static Object makeAddr(VirtualFrame frame, Node inliningTarget, UniversalSockAddr addr, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, - @CachedLibrary("addr") UniversalSockAddrLibrary addrLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, + @Cached PosixSupportNodes.GetCStringAsStringNode getCStringAsStringNode, @Cached PRaiseNode raiseNode) { try { PythonContext context = PythonContext.get(inliningTarget); - int family = addrLib.getFamily(addr); + int family = addr.getFamily(); if (family == AF_INET.value) { - Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - return posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet4SockAddr.getAddressAsBytes())); + Inet4SockAddr inet4SockAddr = addr.asInet4SockAddr(); + PosixSupport posixSupport = context.getPosixSupport(); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet4SockAddr.getAddressAsBytes())); } else if (family == AF_INET6.value) { - Inet6SockAddr inet6SockAddr = addrLib.asInet6SockAddr(addr); - Object posixSupport = context.getPosixSupport(); - return posixLib.getCStringAsString(posixSupport, posixLib.inet_ntop(posixSupport, family, inet6SockAddr.getAddress())); + Inet6SockAddr inet6SockAddr = addr.asInet6SockAddr(); + PosixSupport posixSupport = context.getPosixSupport(); + return getCStringAsStringNode.execute(inliningTarget, posixSupport, posixSupport.inet_ntop(family, inet6SockAddr.getAddress())); } else { throw raiseNode.raise(inliningTarget, NotImplementedError, toTruffleStringUncached("makesockaddr: unknown address family")); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java index e3513ecdb9..c0bb455c1e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketUtils.java @@ -50,11 +50,11 @@ import com.oracle.graal.python.nodes.PConstructAndRaiseNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.PosixConstants; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.SelectResult; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.util.TimeUtils; import com.oracle.truffle.api.frame.Frame; @@ -63,27 +63,23 @@ public class SocketUtils { @FunctionalInterface public interface SocketFunction { - /* - * NB: The library and support need to be passed as arguments and shouldn't be taken from - * the closure. Otherwise, Truffle has trouble inlining the library call. - */ - T run(PosixSupportLibrary posixLib, Object posixSupport) throws PosixException; + T run(PosixSupport posixSupport) throws PosixException; } /** * Rough equivalent of CPython's {@code sock_call}. Takes care of calling select for connections * with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect) throws PosixException { - return callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, posixSupport, gil, socket, function, writing, connect, null); + return callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixSupport, gil, socket, function, writing, connect, null); } /** * Rough equivalent of CPython's {@code sock_call_ex}. Takes care of calling select for * connections with timeouts and retrying the call on EINTR. Must be called with GIL held. */ - public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupportLibrary posixLib, Object posixSupport, GilNode gil, + public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget, PConstructAndRaiseNode.Lazy constructAndRaiseNode, PosixSupport posixSupport, GilNode gil, PSocket socket, SocketFunction function, boolean writing, boolean connect, TimeoutHelper timeoutHelperIn) throws PosixException { TimeoutHelper timeoutHelper = timeoutHelperIn; if (timeoutHelper == null && socket.getTimeoutNs() > 0) { @@ -107,10 +103,10 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget if (PosixConstants.IS_WIN32) { int[] errorfds = connect ? new int[]{socket.getFd()} : EMPTY_INT_ARRAY; if (writing) { - SelectResult selected = posixLib.select(posixSupport, EMPTY_INT_ARRAY, new int[]{socket.getFd()}, errorfds, selectTimeout); + SelectResult selected = posixSupport.select(EMPTY_INT_ARRAY, new int[]{socket.getFd()}, errorfds, selectTimeout); ready = selected.getWriteFds()[0] || connect && selected.getErrorFds()[0]; } else { - SelectResult selected = posixLib.select(posixSupport, new int[]{socket.getFd()}, EMPTY_INT_ARRAY, errorfds, selectTimeout); + SelectResult selected = posixSupport.select(new int[]{socket.getFd()}, EMPTY_INT_ARRAY, errorfds, selectTimeout); ready = selected.getReadFds()[0] || connect && selected.getErrorFds()[0]; } } else { @@ -119,7 +115,7 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget event |= PosixConstants.POLLERR.getValueIfDefined(); } int[] revents = new int[1]; - posixLib.poll(posixSupport, new int[]{socket.getFd()}, new int[]{event}, revents, pollTimeout(selectTimeout)); + posixSupport.poll(new int[]{socket.getFd()}, new int[]{event}, revents, pollTimeout(selectTimeout)); ready = revents[0] != 0; } if (!ready) { @@ -141,7 +137,7 @@ public static T callSocketFunctionWithRetry(Frame frame, Node inliningTarget try { gil.release(true); try { - return function.run(posixLib, posixSupport); + return function.run(posixSupport); } finally { gil.acquire(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java index 913bc283c9..a865e532db 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java @@ -146,6 +146,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -740,7 +741,6 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, @Cached ToByteArrayNode toBytes, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PRaiseNode raiseNode) { if (cafile instanceof PNone && capath instanceof PNone && cadata instanceof PNone) { throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.CA_FILE_PATH_DATA_CANNOT_BE_ALL_OMMITED); @@ -753,7 +753,7 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } final TruffleFile file; if (!(cafile instanceof PNone)) { - file = toTruffleFile(frame, inliningTarget, asPath, cafile, toJavaStringNode, eqNode, constructAndRaiseNode); + file = toTruffleFile(frame, inliningTarget, asPath, cafile, toJavaStringNode, constructAndRaiseNode); if (!file.exists()) { throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, OSErrorEnum.ENOENT); } @@ -762,7 +762,7 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } final TruffleFile path; if (!(capath instanceof PNone)) { - path = toTruffleFile(frame, inliningTarget, asPath, capath, toJavaStringNode, eqNode, constructAndRaiseNode); + path = toTruffleFile(frame, inliningTarget, asPath, capath, toJavaStringNode, constructAndRaiseNode); } else { path = null; } @@ -800,11 +800,11 @@ Object load(VirtualFrame frame, PSSLContext self, Object cafile, Object capath, } private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, PyUnicodeFSDecoderNode asPath, Object fileObject, TruffleString.ToJavaStringNode toJavaStringNode, - TruffleString.EqualNode eqNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { + PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { try { return getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(asPath.execute(frame, fileObject))); } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } @@ -861,7 +861,6 @@ Object load(VirtualFrame frame, PSSLContext self, Object certfile, Object keyfil @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached GetPasswordNode getPasswordNode, @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Cached TruffleString.EqualNode eqNode, @Cached PRaiseNode raiseNode) { if (!PGuards.isString(certfile) && !PGuards.isBytes(certfile)) { throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.S_SHOULD_BE_A_VALID_FILESYSTEMPATH, "certfile"); @@ -870,8 +869,8 @@ Object load(VirtualFrame frame, PSSLContext self, Object certfile, Object keyfil throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.S_SHOULD_BE_A_VALID_FILESYSTEMPATH, "keyfile"); } Object kf = keyfile instanceof PNone ? certfile : keyfile; - TruffleFile certTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, certfile), toJavaStringNode, eqNode, constructAndRaiseNode); - TruffleFile keyTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, kf), toJavaStringNode, eqNode, constructAndRaiseNode); + TruffleFile certTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, certfile), toJavaStringNode, constructAndRaiseNode); + TruffleFile keyTruffleFile = toTruffleFile(frame, inliningTarget, asPath.execute(frame, kf), toJavaStringNode, constructAndRaiseNode); try { try { return load(getContext(), inliningTarget, constructAndRaiseNode, certTruffleFile, keyTruffleFile, null, self); @@ -934,7 +933,7 @@ private static Object load(PythonContext context, Node inliningTarget, PConstruc } } - private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, TruffleString path, TruffleString.ToJavaStringNode toJavaStringNode, TruffleString.EqualNode eqNode, + private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, TruffleString path, TruffleString.ToJavaStringNode toJavaStringNode, PConstructAndRaiseNode.Lazy constructAndRaiseNode) throws PException { try { TruffleFile file = getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(path)); @@ -943,7 +942,7 @@ private TruffleFile toTruffleFile(VirtualFrame frame, Node inliningTarget, Truff } return file; } catch (Exception e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e, eqNode); + throw constructAndRaiseNode.get(inliningTarget).raiseOSError(frame, e); } } } @@ -977,6 +976,7 @@ static char[] doBytes(PBytesLike bytes, for (int i = 0; i < res.length; i++) { res[i] = (char) data[i]; } + LoopNode.reportLoopCount(inliningTarget, res.length); return res; } @@ -1087,11 +1087,14 @@ Object getCerts(VirtualFrame frame, PSSLContext self, @SuppressWarnings("unused" @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { try { List result = PythonUtils.newList(); - for (X509Certificate cert : self.getCACerts()) { + X509Certificate[] certs = self.getCACerts(); + for (int i = 0; i < certs.length; i++) { + X509Certificate cert = certs[i]; if (CertUtils.isCA(cert, CertUtils.getKeyUsage(cert))) { PythonUtils.add(result, CertUtils.decodeCertificate(inliningTarget, constructAndRaiseNode, cert, language)); } } + LoopNode.reportLoopCount(inliningTarget, certs.length); return PFactory.createList(language, PythonUtils.toArray(result)); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateParsingException ex) { throw constructAndRaiseNode.get(inliningTarget).raiseSSLError(frame, SSLErrorCode.ERROR_SSL, ex); @@ -1100,14 +1103,18 @@ Object getCerts(VirtualFrame frame, PSSLContext self, @SuppressWarnings("unused" @Specialization(guards = "binary_form") static Object getCertsBinary(PSSLContext self, @SuppressWarnings("unused") boolean binary_form, + @Bind Node inliningTarget, @Bind PythonLanguage language) { try { List result = PythonUtils.newList(); - for (X509Certificate cert : self.getCACerts()) { + X509Certificate[] certs = self.getCACerts(); + for (int i = 0; i < certs.length; i++) { + X509Certificate cert = certs[i]; if (CertUtils.isCA(cert, CertUtils.getKeyUsage(cert))) { PythonUtils.add(result, PFactory.createBytes(language, CertUtils.getEncoded(cert))); } } + LoopNode.reportLoopCount(inliningTarget, certs.length); return PFactory.createList(language, PythonUtils.toArray(result)); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateEncodingException ex) { throw PConstructAndRaiseNode.raiseUncachedSSLError(SSLErrorCode.ERROR_SSL, ex); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java index 82bd4f07c2..44aa301295 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLOperationNode.java @@ -60,8 +60,7 @@ import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.util.OverflowException; @@ -73,7 +72,6 @@ import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; /** @@ -171,7 +169,6 @@ protected enum SSLOperation { @Specialization(guards = "socket.getSocket() != null") static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, ByteBuffer appInput, ByteBuffer targetBuffer, SSLOperation operation, - @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @Cached(inline = false) GilNode gil, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { @@ -222,8 +219,8 @@ static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, byte[] bytes1 = networkInboundBIO.getInternalBytes(); int offset1 = networkInboundBIO.getWritePosition(); try { - int recvlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket.getSocket(), - (p, s) -> p.recv(s, socket.getSocket().getFd(), bytes1, offset1, len1, 0), + int recvlen = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket.getSocket(), + s -> s.recv(socket.getSocket().getFd(), bytes1, offset1, len1, 0), true, false, timeoutHelper); if (recvlen == 0) { // This means EOF @@ -249,8 +246,8 @@ static void doSocket(VirtualFrame frame, Node inliningTarget, PSSLSocket socket, int offset2 = networkOutboundBIO.getReadPosition(); int len2 = networkOutboundBIO.getPending(); try { - int writtenBytes = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, socket.getSocket(), - (p, s) -> p.send(s, socket.getSocket().getFd(), bytes2, offset2, len2, 0), + int writtenBytes = SocketUtils.callSocketFunctionWithRetry(frame, inliningTarget, constructAndRaiseNode, context.getPosixSupport(), gil, socket.getSocket(), + s -> s.send(socket.getSocket().getFd(), bytes2, offset2, len2, 0), true, false, timeoutHelper); networkOutboundBIO.advanceReadPosition(writtenBytes); } catch (PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java index 286809358a..396bf4aa4c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java @@ -188,6 +188,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -704,9 +705,11 @@ static boolean doTuple(Object selfObj, Object subStrs, int start, int end, Op op TruffleString subStr = castPrefixNode.cast(inliningTarget, element, ErrorMessages.INVALID_ELEMENT_TYPE, op.methodName(), element); int subStrLen = codePointLengthNode.execute(subStr, TS_ENCODING); if (doIt(self, subStr, cpStart, cpEnd, selfLen, subStrLen, regionEqualNode, op)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, storage.length()); return false; } @@ -871,6 +874,7 @@ static int count(TruffleString self, TruffleString sub, int start, int end, cnt++; pos = i + subLen; } + LoopNode.reportLoopCount(indexOfStringNode, cnt); return cnt; } @@ -1035,6 +1039,7 @@ static PDict doString(VirtualFrame frame, Object cls, Object from, Object to, Ob int value = nextNode.execute(toIt, TS_ENCODING); storage = setHashingStorageItem.execute(frame, inliningTarget, storage, key, value); } + LoopNode.reportLoopCount(inliningTarget, fromLen); assert !toIt.hasNext(); if (hasZ) { TruffleStringIterator zIt = createCodePointIteratorNode.execute(zString, TS_ENCODING); @@ -1307,6 +1312,7 @@ static PList doStringSep(TruffleString self, TruffleString sep, int maxsplit, appendNode.execute(list, substringNode.execute(self, lastEnd, nextIndex - lastEnd, TS_ENCODING, false)); lastEnd = nextIndex + sepLen; } + LoopNode.reportLoopCount(inliningTarget, (maxsplit < 0 ? Integer.MAX_VALUE : maxsplit) - splits); appendNode.execute(list, substringNode.execute(self, lastEnd, selfLen - lastEnd, TS_ENCODING, false)); return list; } @@ -1367,7 +1373,7 @@ private static PList splitfields(TruffleString s, int maxsplit, AppendNode appen // Start next segment search at that point start = index; } - + LoopNode.reportLoopCount(appendNode, splits); return list; } } @@ -1416,6 +1422,7 @@ static PList doStringSepMaxsplit(VirtualFrame frame, TruffleString self, Truffle end = idx; splits++; } + LoopNode.reportLoopCount(inliningTarget, splits); appendNode.execute(list, substringNode.execute(self, 0, end, TS_ENCODING, true)); reverseNode.execute(frame, list); @@ -1447,8 +1454,8 @@ static PList doStringMaxsplit(VirtualFrame frame, TruffleString s, @SuppressWarn // emitted in ws->non-ws transition and at the end boolean hasSegment = false; int start = 0, end = length, splits = 0; - - for (int i = length - 1; i >= 0; i--) { + int i = length - 1; + for (; i >= 0; i--) { if (StringUtils.isSpace(codePointAtIndexNode.execute(s, i))) { if (hasSegment) { appendNode.execute(list, substringNode.execute(s, start, end - start, TS_ENCODING, false)); @@ -1464,6 +1471,7 @@ static PList doStringMaxsplit(VirtualFrame frame, TruffleString s, @SuppressWarn start = i; } } + LoopNode.reportLoopCount(inliningTarget, length - 1 - i); if (hasSegment) { appendNode.execute(list, substringNode.execute(s, 0, end, TS_ENCODING, false)); } @@ -1545,6 +1553,7 @@ static PList doStringKeepends(Node inliningTarget, TruffleString self, boolean k TruffleString line = substringNode.execute(self, substringStartByteIndex, substringByteLength, TS_ENCODING, false); appendNode.execute(list, line); } while (matchFound); + LoopNode.reportLoopCount(inliningTarget, list.getSequenceStorage().length()); return list; } @@ -2276,6 +2285,7 @@ static TruffleString doString(TruffleString self, } end++; } + LoopNode.reportLoopCount(nextNode, end); if (start != end) { appendSegment(self, language, appendStringNode, substringNode, toJavaStringNode, fromJavaStringNode, sb, start, end - 1); } @@ -2432,6 +2442,7 @@ static TruffleString doGenericCachedStep(TruffleString value, SliceInfo slice, appendCodePointNode.execute(sb, codePointAtIndexNode.execute(value, i), 1, true); j++; } + LoopNode.reportLoopCount(inliningTarget, len); return toStringNode.execute(sb); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java index 95b83c24f3..9c9dfc5ad9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringNodes.java @@ -104,6 +104,7 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -477,6 +478,7 @@ static TruffleString doPSequence(TruffleString self, PSequence sequence, item = getItemNode.execute(storage, i); appendStringNode.execute(sb, castToStringNode.execute(inliningTarget, item)); } + LoopNode.reportLoopCount(inliningTarget, len - 1); return toStringNode.execute(sb); } catch (OutOfMemoryError e) { throw raise.raise(inliningTarget, MemoryError); @@ -679,6 +681,7 @@ public abstract static class StringReplaceNode extends Node { @Specialization static TruffleString doReplace(TruffleString self, TruffleString old, TruffleString with, int maxCountArg, + @Bind Node inliningTarget, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfStringNode indexOfStringNode, @Cached TruffleString.SubstringNode substringNode, @@ -702,16 +705,20 @@ static TruffleString doReplace(TruffleString self, TruffleString old, TruffleStr int replacements = 0; TruffleStringIterator it = createCodePointIteratorNode.execute(self, TS_ENCODING); int i = 0; - while (it.hasNext()) { - if (replacements++ >= maxCount) { - TruffleString rest = substringNode.execute(self, i, selfCpLen - i, TS_ENCODING, true); - appendStringNode.execute(sb, rest); - return toStringNode.execute(sb); + try { + while (it.hasNext()) { + if (replacements++ >= maxCount) { + TruffleString rest = substringNode.execute(self, i, selfCpLen - i, TS_ENCODING, true); + appendStringNode.execute(sb, rest); + return toStringNode.execute(sb); + } + appendStringNode.execute(sb, with); + int codePoint = nextNode.execute(it, TS_ENCODING); + appendCodePointNode.execute(sb, codePoint, 1, true); + ++i; } - appendStringNode.execute(sb, with); - int codePoint = nextNode.execute(it, TS_ENCODING); - appendCodePointNode.execute(sb, codePoint, 1, true); - ++i; + } finally { + LoopNode.reportLoopCount(inliningTarget, i); } if (replacements < maxCount) { appendStringNode.execute(sb, with); @@ -737,6 +744,7 @@ static TruffleString doReplace(TruffleString self, TruffleString old, TruffleStr } idx = indexOfStringNode.execute(self, old, start, selfCpLen, TS_ENCODING); } while (idx >= 0); + LoopNode.reportLoopCount(inliningTarget, replacements); TruffleString rest = substringNode.execute(self, start, selfCpLen - start, TS_ENCODING, true); appendStringNode.execute(sb, rest); return toStringNode.execute(sb); @@ -756,6 +764,7 @@ public abstract static class StringReprNode extends Node { @Specialization static TruffleString doString(TruffleString self, + @Bind Node inliningTarget, @Cached TruffleString.CodePointLengthNode codePointLengthNode, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, @Cached TruffleString.CreateCodePointIteratorNode createCodePointIteratorNode, @@ -802,6 +811,7 @@ static TruffleString doString(TruffleString self, break; } } + LoopNode.reportLoopCount(inliningTarget, selfLen); appendCodePointNode.execute(sb, (byte) (useDoubleQuotes ? '"' : '\''), 1, true); return toStringNode.execute(sb); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java index a88f049a89..210150954b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringUtils.java @@ -182,6 +182,7 @@ public static TruffleString strip(TruffleString str, StripKind stripKind, Truffl j++; } + LoopNode.reportLoopCount(substringNode, len - j + i); return substringNode.execute(str, i, j - i, TS_ENCODING, false); } @@ -215,6 +216,7 @@ public static TruffleString strip(TruffleString str, TruffleString chars, StripK j++; } + LoopNode.reportLoopCount(substringNode, len - j + i); return substringNode.execute(str, i, j - i, TS_ENCODING, false); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java index 7f14c44e24..14f4fd1aa0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/struct/StructBuiltins.java @@ -114,6 +114,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -130,6 +131,7 @@ static void packInternal(VirtualFrame frame, PStruct self, StructNodes.PackValue buffer_offset += code.size; } } + LoopNode.reportLoopCount(packValueNode, (int) Math.min(Integer.MAX_VALUE, (long) codes.length + pos)); } public static Object[] unpackInternal(PStruct self, StructNodes.UnpackValueNode unpackValueNode, byte[] bytes, int offset) { @@ -144,6 +146,7 @@ public static Object[] unpackInternal(PStruct self, StructNodes.UnpackValueNode buffer_offset += code.size; } } + LoopNode.reportLoopCount(unpackValueNode, (int) Math.min(Integer.MAX_VALUE, (long) codes.length + pos)); return values; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java index 30912d0891..f7a29ee665 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/InstantiableStructSequenceBuiltins.java @@ -71,6 +71,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -162,6 +163,7 @@ static PTuple withDict(VirtualFrame frame, Object cls, Object sequence, Object d dst[i] = PNone.NONE; } } + LoopNode.reportLoopCount(inliningTarget, dst.length); return PFactory.createTuple(cls, getInstanceShape.execute(cls), new ObjectSequenceStorage(dst, minLen)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java index 5980476d9a..7a48ac9df7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequenceBuiltins.java @@ -99,6 +99,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; @@ -219,6 +220,7 @@ static TruffleString repr(VirtualFrame frame, PTuple self, appendStringNode.execute(sb, T_EQ); appendStringNode.execute(sb, reprNode.execute(frame, inliningTarget, getItemNode.execute(inliningTarget, tupleStore, i))); } + LoopNode.reportLoopCount(inliningTarget, visibleSize - 1); } appendStringNode.execute(sb, T_RPAREN); return toStringNode.execute(sb); @@ -259,6 +261,7 @@ static PTuple reduce(VirtualFrame frame, PTuple self, // We're reading past length, GetItemScalarNode doesn't do a bounds check dictSetItem.execute(inliningTarget, dict, n, getSeqItem.execute(inliningTarget, storage, i)); } + LoopNode.reportLoopCount(inliningTarget, nFields - nVisibleFields); } return PFactory.createTuple(language, new Object[]{type, PFactory.createTuple(language, new Object[]{tuple, dict})}); } @@ -294,6 +297,7 @@ static PTuple replace(VirtualFrame frame, PTuple self, @SuppressWarnings("unused for (int i = 0; i < nFields; i++) { values[i] = getItemNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, nFields); TruffleString[] fieldNames = getFieldNamesNode.execute(inliningTarget, type); boolean[] matched = new boolean[changes.length]; @@ -306,6 +310,7 @@ static PTuple replace(VirtualFrame frame, PTuple self, @SuppressWarnings("unused } } } + LoopNode.reportLoopCount(inliningTarget, nFields); checkUnexpected(changes, matched, inliningTarget, raiseNode, language); return PFactory.createTuple(type, getInstanceShapeNode.execute(type), new ObjectSequenceStorage(values, storage.length())); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java index b91de2043f..58d983c819 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleBuiltins.java @@ -107,6 +107,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -218,6 +219,7 @@ static long count(VirtualFrame frame, Object self, Object value, count++; } } + LoopNode.reportLoopCount(inliningTarget, tupleStore.length()); return count; } } @@ -273,6 +275,7 @@ public static TruffleString repr(VirtualFrame frame, Object self, appendStringNode.execute(buf, toString(frame, inliningTarget, getItemNode.execute(tupleStore, i), reprNode)); appendStringNode.execute(buf, T_COMMA_SPACE); } + LoopNode.reportLoopCount(inliningTarget, len - 1); if (len > 0) { appendStringNode.execute(buf, toString(frame, inliningTarget, getItemNode.execute(tupleStore, len - 1), reprNode)); @@ -482,6 +485,7 @@ private static long doComputeHash(VirtualFrame frame, Node inliningTarget, Seque hash = (hash ^ tmp) * multiplier; multiplier += 82520 + len + len; } + LoopNode.reportLoopCount(inliningTarget, len); hash += 97531; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java index a7f65a0181..88cd6e0912 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java @@ -401,7 +401,9 @@ Object generic(@SuppressWarnings("unused") Object cls, @SuppressWarnings("unused private Object calculateMetaclass(VirtualFrame frame, Node inliningTarget, Object cls, PTuple bases, GetClassNode getClassNode, IsTypeNode isTypeNode, PyObjectLookupAttr lookupMroEntries, GetObjectArrayNode getObjectArrayNode) { Object winner = cls; - for (Object base : getObjectArrayNode.execute(inliningTarget, bases)) { + Object[] basesArray = getObjectArrayNode.execute(inliningTarget, bases); + for (int i = 0; i < basesArray.length; i++) { + Object base = basesArray[i]; if (!isTypeNode.execute(inliningTarget, base) && lookupMroEntries.execute(frame, inliningTarget, base, T___MRO_ENTRIES__) != NO_VALUE) { throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.TYPE_DOESNT_SUPPORT_MRO_ENTRY_RESOLUTION); } @@ -417,6 +419,7 @@ private Object calculateMetaclass(VirtualFrame frame, Node inliningTarget, Objec } throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.METACLASS_CONFLICT); } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); return winner; } @@ -739,6 +742,7 @@ static Object setBases(VirtualFrame frame, PythonClass cls, Object value, throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MUST_BE_TUPLE_OF_CLASSES_NOT_P, cls, "__bases__", a[i]); } } + LoopNode.reportLoopCount(inliningTarget, a.length); Object newBestBase = getBestBase.execute(inliningTarget, baseClasses); if (newBestBase == null) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java index d187c24935..52aee987f2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeNodes.java @@ -242,6 +242,7 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.ControlFlowException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -816,7 +817,7 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj SequenceStorage storage = tuple.getSequenceStorage(); Object[] values = toArrayNode.execute(inliningTarget, storage); try { - return cast(values, storage); + return cast(inliningTarget, values, storage); } catch (ClassCastException e) { throw raise.raise(inliningTarget, PythonBuiltinClassType.SystemError, ErrorMessages.UNSUPPORTED_OBJ_IN, "tp_bases"); } @@ -824,7 +825,7 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj int length = Math.toIntExact(readLongField(nativeTuple.getPtr(), CFields.PyVarObject__ob_size)); Object[] values = getTpBasesNode.readPyObjectArray(CStructAccess.getFieldPtr(nativeTuple.getPtr(), PyTupleObject__ob_item), length); try { - return cast(values, length); + return cast(inliningTarget, values, length); } catch (ClassCastException e) { throw raise.raise(inliningTarget, PythonBuiltinClassType.SystemError, ErrorMessages.UNSUPPORTED_OBJ_IN, "tp_bases"); } @@ -833,15 +834,16 @@ static PythonAbstractClass[] doNative(Node inliningTarget, PythonNativeClass obj } // TODO: get rid of this - private static PythonAbstractClass[] cast(Object[] arr, SequenceStorage storage) { - return cast(arr, storage.length()); + private static PythonAbstractClass[] cast(Node inliningTarget, Object[] arr, SequenceStorage storage) { + return cast(inliningTarget, arr, storage.length()); } - private static PythonAbstractClass[] cast(Object[] arr, int length) { + private static PythonAbstractClass[] cast(Node inliningTarget, Object[] arr, int length) { PythonAbstractClass[] bases = new PythonAbstractClass[length]; for (int i = 0; i < length; i++) { bases[i] = (PythonAbstractClass) arr[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return bases; } } @@ -942,6 +944,7 @@ private static PythonAbstractClass bestBase(Node inliningTarget, PythonAbstractC throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.MULTIPLE_BASES_LAYOUT_CONFLICT); } } + LoopNode.reportLoopCount(inliningTarget, bases.length); return base; } } @@ -2049,6 +2052,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple throw raise.raise(inliningTarget, PythonBuiltinClassType.NotImplementedError, ErrorMessages.CREATING_CLASS_NON_CLS_BASES); } } + LoopNode.reportLoopCount(inliningTarget, array.length); } // check for possible layout conflicts PythonAbstractClass base = getBestBaseNode.execute(inliningTarget, basesArray); @@ -2139,6 +2143,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple ctx.addWeak = true; } } + LoopNode.reportLoopCount(inliningTarget, slotlen); // Make slots into a tuple Object state = BoundaryCallContext.enter(frame, language, context, boundaryCallData); try { @@ -2150,7 +2155,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple BoundaryCallContext.exit(frame, language, context, state); } /* Secondary bases may provide weakrefs or dict */ - typeNewSlotBases(ctx, base, basesArray); + typeNewSlotBases(inliningTarget, ctx, base, basesArray); } int indexedSlotCount = getIndexedSlotsCountNode.execute(inliningTarget, base); @@ -2159,6 +2164,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple IndexedSlotDescriptor slotDesc = PFactory.createIndexedSlotDescriptor(language, slotName, indexedSlotCount++, pythonClass); pythonClass.setAttribute(slotName, slotDesc); } + LoopNode.reportLoopCount(inliningTarget, ctx.copiedSlots.length); } pythonClass.setIndexedSlotCount(indexedSlotCount); @@ -2179,7 +2185,7 @@ static PythonClass typeMetaclass(VirtualFrame frame, TruffleString name, PTuple } // equivalent of type_new_slot_bases in CPython - private static void typeNewSlotBases(TypeNewContext ctx, Object primaryBase, PythonAbstractClass[] basesArray) { + private static void typeNewSlotBases(Node inliningTarget, TypeNewContext ctx, Object primaryBase, PythonAbstractClass[] basesArray) { if (basesArray.length > 1 && (ctx.mayAddDict && !ctx.addDict || ctx.mayAddWeak && !ctx.addWeak)) { for (PythonAbstractClass base : basesArray) { if (base == primaryBase) { @@ -2196,6 +2202,7 @@ private static void typeNewSlotBases(TypeNewContext ctx, Object primaryBase, Pyt break; } } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java index 5fdd80f32a..5b307050fc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/slots/TpSlotVarargs.java @@ -41,11 +41,16 @@ package com.oracle.graal.python.builtins.objects.type.slots; import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyObject__ob_type; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_flags; +import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_vectorcall_offset; +import static com.oracle.graal.python.builtins.objects.type.TypeFlags.HAVE_VECTORCALL; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___CALL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INIT__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___NEW__; import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; +import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import java.lang.ref.Reference; @@ -55,9 +60,11 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.cext.PythonNativeObject; import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionInvoker; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CreateNativeArgsTupleNode; +import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CreateNativeKwNamesTupleNode; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.EagerTupleState; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper; import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PyObjectCheckFunctionResultNode; @@ -66,6 +73,8 @@ import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeToPythonInternalNode; import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.PythonToNativeInternalNode; import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.TransformExceptionFromNativeNode; +import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess; +import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; @@ -99,13 +108,17 @@ import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; +import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonContext.GetThreadStateNode; import com.oracle.graal.python.runtime.PythonContext.PythonThreadState; +import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.RootCallTarget; @@ -124,7 +137,9 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; public final class TpSlotVarargs { @@ -314,16 +329,109 @@ static Object callPython(VirtualFrame frame, Node inliningTarget, TpSlotPythonSi } } - private static final CApiTiming C_API_TIMING = CApiTiming.create(true, ""); + private static final CApiTiming C_API_TIMING_TP_CALL = CApiTiming.create(true, "tp_call"); + private static final CApiTiming C_API_TIMING_TP_INIT = CApiTiming.create(true, "tp_init"); + private static final CApiTiming C_API_TIMING_TP_NEW = CApiTiming.create(true, "tp_new"); + private static final CApiTiming C_API_TIMING_VECTORCALL = CApiTiming.create(true, "vectorcall"); + + @GenerateInline(false) + @GenerateUncached + abstract static class CallNativeVectorcallNode extends Node { + + abstract Object execute(VirtualFrame frame, Object callable, long vectorcallPointer, Object[] args, PKeyword[] keywords); + + @Specialization + static Object callNative(VirtualFrame frame, Object callable, long vectorcallPointer, Object[] args, PKeyword[] keywords, + @Bind Node inliningTarget, + @Bind PythonContext context, + @Cached GetThreadStateNode getThreadStateNode, + @Cached EnsurePythonObjectNode ensurePythonObjectNode, + @Cached PythonToNativeInternalNode toNativeNode, + @Cached CreateNativeKwNamesTupleNode createNativeKwNamesTupleNode, + @Cached ReleaseNativeArgsTupleNode releaseNativeKwNamesTupleNode, + @Cached NativeToPythonInternalNode toPythonNode, + @Cached PyObjectCheckFunctionResultNode checkResultNode, + @Cached("createFor($node)") BoundaryCallData boundaryCallData) { + PythonThreadState threadState = getThreadStateNode.execute(inliningTarget, context); + Object promotedCallable = ensurePythonObjectNode.execute(context, callable, false); + Object[] fastcallArgs = new Object[args.length + keywords.length]; + for (int i = 0; i < args.length; i++) { + fastcallArgs[i] = ensurePythonObjectNode.execute(context, args[i], false); + } + LoopNode.reportLoopCount(inliningTarget, args.length); + + long nativeArgs = NULLPTR; + Object[] keywordNames = null; + long keywordNamesPtr = NULLPTR; + try { + if (keywords.length > 0) { + keywordNames = new Object[keywords.length]; + for (int i = 0; i < keywords.length; i++) { + keywordNames[i] = keywords[i].getName(); + fastcallArgs[args.length + i] = ensurePythonObjectNode.execute(context, keywords[i].getValue(), false); + } + LoopNode.reportLoopCount(inliningTarget, keywordNames.length); + keywordNamesPtr = createNativeKwNamesTupleNode.execute(context, keywordNames); + } + nativeArgs = createNativeArguments(fastcallArgs, toNativeNode, inliningTarget); + + long nativeResult = invokeVectorcall(frame, vectorcallPointer, context, boundaryCallData, threadState, + toNativeNode.execute(inliningTarget, promotedCallable), nativeArgs, args.length, keywordNamesPtr); + return checkResultNode.execute(threadState, T___CALL__, toPythonNode.executeTransferAndRelease(inliningTarget, nativeResult)); + } finally { + if (nativeArgs != NULLPTR) { + NativeMemory.free(nativeArgs); + } + if (keywordNames != null) { + releaseNativeKwNamesTupleNode.execute(keywordNamesPtr, keywordNames); + } + Reference.reachabilityFence(promotedCallable); + Reference.reachabilityFence(fastcallArgs); + Reference.reachabilityFence(keywordNames); + } + } + + private static long createNativeArguments(Object[] args, PythonToNativeInternalNode toNativeNode, Node inliningTarget) { + if (args.length == 0) { + return NULLPTR; + } + long pointer = NativeMemory.mallocPtrArray(args.length); + for (int i = 0; i < args.length; i++) { + assert EnsurePythonObjectNode.doesNotNeedPromotion(args[i]); + NativeMemory.writePtrArrayElement(pointer, i, toNativeNode.execute(inliningTarget, args[i])); + } + LoopNode.reportLoopCount(inliningTarget, args.length); + return pointer; + } + + private static long invokeVectorcall(VirtualFrame frame, long vectorcallPointer, PythonContext context, BoundaryCallData boundaryCallData, PythonThreadState threadState, + long callable, long args, long nargs, long keywordNames) { + Object state = BoundaryCallContext.enter(frame, threadState, boundaryCallData); + CApiTiming.enter(); + try { + return ExternalFunctionInvoker.invokeVECTORCALL(vectorcallPointer, callable, args, nargs, keywordNames); + } catch (Throwable exception) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + GilNode.uncachedAcquire(); + throw CompilerDirectives.shouldNotReachHere(exception); + } finally { + CApiTiming.exit(C_API_TIMING_VECTORCALL); + if (frame != null && threadState.getCaughtException() != null) { + PArguments.setException(frame, threadState.getCaughtException()); + } + BoundaryCallContext.exit(frame, threadState, state); + } + } + } @GenerateInline(false) @GenerateUncached abstract static class CallNativeTernaryfuncNode extends Node { - abstract Object execute(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name); + abstract Object execute(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, CApiTiming timing); @Specialization - static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, + static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, TruffleString name, CApiTiming timing, @Bind Node inliningTarget, @Bind PythonContext context, @Cached GetThreadStateNode getThreadStateNode, @@ -351,7 +459,7 @@ static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object kwargsDict = keywords.length > 0 ? PFactory.createDict(language, keywords) : NO_VALUE; assert EnsurePythonObjectNode.doesNotNeedPromotion(kwargsDict); try { - long nativeResult = ExternalFunctionInvoker.invokeTERNARYFUNC(frame, C_API_TIMING, context.ensureNativeContext(), boundaryCallData, state, slot.callable, + long nativeResult = ExternalFunctionInvoker.invokeTERNARYFUNC(frame, timing, context.ensureNativeContext(), boundaryCallData, state, slot.callable, toNativeNode.execute(inliningTarget, promotedSelf), argsTuplePtr, toNativeNode.execute(inliningTarget, kwargsDict)); @@ -419,7 +527,7 @@ static Object callNative(VirtualFrame frame, Node inliningTarget, TpSlotCExtNati Object kwargsDict = keywords.length > 0 ? PFactory.createDict(language, keywords) : NO_VALUE; assert EnsurePythonObjectNode.doesNotNeedPromotion(kwargsDict); try { - int nativeResult = ExternalFunctionInvoker.invokeINITPROC(frame, C_API_TIMING, context.ensureNativeContext(), boundaryCallData, state, slot.callable, + int nativeResult = ExternalFunctionInvoker.invokeINITPROC(frame, C_API_TIMING_TP_INIT, context.ensureNativeContext(), boundaryCallData, state, slot.callable, toNativeNode.execute(inliningTarget, promotedSelf), argsTuplePtr, toNativeNode.execute(inliningTarget, kwargsDict)); @@ -512,7 +620,7 @@ static boolean hasDefaultMetatype(Node inliningTarget, Object self, GetClassNode static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, @Cached CallNativeTernaryfuncNode callNode) { // 'tp_new' slot's C type is actually 'newfunc' but that is compatible to 'ternaryfunc'. - return callNode.execute(frame, slot, self, args, keywords, T___NEW__); + return callNode.execute(frame, slot, self, args, keywords, T___NEW__, C_API_TIMING_TP_NEW); } } @@ -535,9 +643,29 @@ static Object callPython(VirtualFrame frame, Node inliningTarget, TpSlotPythonSi @Specialization @InliningCutoff - static Object callNative(VirtualFrame frame, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, + static Object callNative(VirtualFrame frame, Node inliningTarget, TpSlotCExtNative slot, Object self, Object[] args, PKeyword[] keywords, + @Cached InlinedConditionProfile vectorcallProfile, + @Cached CallNativeVectorcallNode callVectorcallNode, @Cached CallNativeTernaryfuncNode callNode) { - return callNode.execute(frame, slot, self, args, keywords, T___CALL__); + if (self instanceof PythonNativeObject nativeObject) { + long vectorcallPointer = getVectorcallPointer(nativeObject); + if (vectorcallProfile.profile(inliningTarget, vectorcallPointer != NULLPTR)) { + return callVectorcallNode.execute(frame, self, vectorcallPointer, args, keywords); + } + } + return callNode.execute(frame, slot, self, args, keywords, T___CALL__, C_API_TIMING_TP_CALL); + } + + /** Reads the vectorcall pointer without resolving any native object or its type. */ + private static long getVectorcallPointer(PythonNativeObject callable) { + long callablePtr = callable.getPtr(); + long obType = CStructAccess.readPtrField(callablePtr, PyObject__ob_type); + if ((CStructAccess.readLongField(obType, PyTypeObject__tp_flags) & HAVE_VECTORCALL) == 0) { + return NULLPTR; + } + long vectorcallOffset = CStructAccess.readLongField(obType, PyTypeObject__tp_vectorcall_offset); + assert vectorcallOffset > 0; + return NativeMemory.readPtr(callablePtr + vectorcallOffset); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java index 625397545d..7325e16c0c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/types/UnionTypeBuiltins.java @@ -98,6 +98,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -240,6 +241,7 @@ static boolean check(VirtualFrame frame, PUnionType self, Object other, // Cannot break here, the check for GenericAlias needs to check all args } } + LoopNode.reportLoopCount(inliningTarget, argsStorage.length()); return result; } } @@ -269,6 +271,7 @@ static boolean check(VirtualFrame frame, PUnionType self, Object other, // Cannot break here, the check for GenericAlias needs to check all args } } + LoopNode.reportLoopCount(inliningTarget, argsStorage.length()); return result; } } @@ -315,6 +318,7 @@ Object getitem(VirtualFrame frame, PUnionType self, Object item, for (int i = 1; i < newargs.length; i++) { result = orNode.execute(frame, result, newargs[i]); } + LoopNode.reportLoopCount(inliningTarget, newargs.length - 1); return result; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java index 69550330c5..b99e4689ed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyDictMerge.java @@ -76,6 +76,7 @@ import com.oracle.truffle.api.dsl.GenerateUncached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -138,6 +139,7 @@ static void doMerge(VirtualFrame frame, Node inliningTarget, Object target, PDic throw raiseNode.raise(inliningTarget, RuntimeError, ErrorMessages.MUTATED_DURING_UPDATE, "dict"); } } + LoopNode.reportLoopCount(inliningTarget, initialSize); updateStorageNode.execute(inliningTarget, target, targetStorage, newStorage); } } @@ -165,6 +167,7 @@ static void doMerge(VirtualFrame frame, Node inliningTarget, Object target, Obje Object value = getItem.execute(frame, inliningTarget, mapping, key); setItem.execute(frame, inliningTarget, target, key, value); } + LoopNode.reportLoopCount(inliningTarget, keysLen); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java index 3c38a181ec..0735ebd7fa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectGetMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -43,10 +43,13 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; +import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject; import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TpSlots.GetCachedTpSlotsNode; import com.oracle.graal.python.builtins.objects.type.TpSlots.GetObjectSlotsNode; +import com.oracle.graal.python.builtins.objects.type.TypeFlags; +import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.CallSlotDescrGet; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrSet; @@ -110,6 +113,7 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, @Cached GetCachedTpSlotsNode getTypeSlotsNode, @Bind("getClass.execute(inliningTarget, receiver)") Object lazyClass, @Cached LookupAttributeInMRONode.Dynamic lookupNode, + @Cached(inline = false) GetTypeFlagsNode getTypeFlagsNode, @Cached GetObjectSlotsNode getSlotsNode, @Cached CallSlotDescrGet callGetNode, @Cached ReadAttributeFromObjectNode readAttr, @@ -124,7 +128,7 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, TpSlot getMethod = null; if (descr != PNone.NO_VALUE) { hasDescr.enter(inliningTarget); - if (MaybeBindDescriptorNode.isMethodDescriptor(descr)) { + if (isMethodDescriptor(inliningTarget, descr, getClass, getTypeFlagsNode)) { methodFound = true; } else { // lookupGet acts as branch profile for this branch @@ -159,6 +163,18 @@ static Object getAttr(VirtualFrame frame, Node inliningTarget, Object receiver, throw raiseNode.raiseAttributeError(inliningTarget, ErrorMessages.OBJ_P_HAS_NO_ATTR_S, receiver, name); } + private static boolean isMethodDescriptor(Node inliningTarget, Object descriptor, GetClassNode getClassNode, + GetTypeFlagsNode getTypeFlagsNode) { + if (MaybeBindDescriptorNode.isMethodDescriptor(descriptor)) { + return true; + } + if (descriptor instanceof PythonAbstractNativeObject) { + Object descriptorType = getClassNode.execute(inliningTarget, descriptor); + return (getTypeFlagsNode.execute(descriptorType) & TypeFlags.METHOD_DESCRIPTOR) != 0; + } + return false; + } + @Specialization(guards = "isForeignObject(inliningTarget, isForeignObjectNode, receiver)", limit = "1") @InliningCutoff static Object getForeignMethod(VirtualFrame frame, Node inliningTarget, Object receiver, TruffleString name, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java index 58c19a75d5..ef2c3a07c0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyObjectRecursiveBinaryCheckNode.java @@ -59,6 +59,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.UnadoptableNode; @@ -130,11 +131,14 @@ private boolean callRecursiveWithNodeTruffleBoundary(Node inliningTarget, Object private static boolean loopRecursive(VirtualFrame frame, Object arg, Object clsTuple, Node inliningTarget, TupleNodes.GetTupleStorage getTupleStorage, SequenceStorageNodes.ToArrayNode toArrayNode, PyObjectRecursiveBinaryCheckNode node, int depth) { - for (Object cls : getTupleArray(inliningTarget, clsTuple, getTupleStorage, toArrayNode)) { - if (node.executeInternal(frame, arg, cls, depth)) { + Object[] classes = getTupleArray(inliningTarget, clsTuple, getTupleStorage, toArrayNode); + for (int i = 0; i < classes.length; i++) { + if (node.executeInternal(frame, arg, classes[i], depth)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, classes.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java index 6088c97134..d5c53cab02 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyTraceBackPrint.java @@ -254,9 +254,9 @@ protected static TruffleString getIndent(int indent) { protected static CharSequence getSourceLine(TruffleString fileName, int lineNo) { final PythonContext context = PythonContext.get(null); - TruffleFile file = null; + TruffleFile file; try { - file = context.getPublicTruffleFileRelaxed(fileName, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); + file = context.getPublicTruffleFileRelaxed(fileName.toJavaStringUncached(), PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (IllegalArgumentException | SecurityException | UnsupportedOperationException e) { return null; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java index 14be27f2ce..8c4bd448f0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/lib/PyUnicodeEncodeFSDefaultNode.java @@ -49,6 +49,7 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.modules.CodecsModuleBuiltins; import com.oracle.graal.python.nodes.PNodeWithContext; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; @@ -66,6 +67,12 @@ @GenerateCached(false) @GenerateInline public abstract class PyUnicodeEncodeFSDefaultNode extends PNodeWithContext { + + @TruffleBoundary + public static byte[] executeUncached(TruffleString string) { + return PyUnicodeEncodeFSDefaultNodeGen.getUncached().execute(null, null, string); + } + public abstract byte[] execute(Frame frame, Node inliningTarget, TruffleString string); @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java index e8c7d2ad1d..c3b1c1ec55 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java @@ -1155,6 +1155,11 @@ public abstract class ErrorMessages { public static final TruffleString DETACHED_BUFFER = tsLiteral("underlying buffer has been detached"); public static final TruffleString UNSUPPORTED_WHENCE = tsLiteral("whence value %d unsupported"); public static final TruffleString IO_CLOSED = tsLiteral("I/O operation on closed file."); + public static final TruffleString CANNOT_OPEN_CONSOLE_INPUT_BUFFER_FOR_WRITING = tsLiteral("Cannot open console input buffer for writing"); + public static final TruffleString CANNOT_OPEN_NON_CONSOLE_FILE = tsLiteral("Cannot open non-console file"); + public static final TruffleString CONSOLE_BUFFER_DOES_NOT_SUPPORT_WRITING = tsLiteral("Console buffer does not support writing"); + public static final TruffleString CONSOLE_INPUT_IS_NOT_SUPPORTED = tsLiteral("Console input is not supported"); + public static final TruffleString MUST_HAVE_EXACTLY_ONE_OF_READ_WRITE_MODE = tsLiteral("Must have exactly one of read or write mode"); public static final TruffleString MUST_BE_NON_NEG_OR_NEG_1 = tsLiteral("read length must be non-negative or -1"); public static final TruffleString BUF_SIZE_POS = tsLiteral("buffer size must be strictly positive"); public static final TruffleString S_SHOULD_RETURN_BYTES = tsLiteral("%s should return bytes"); @@ -1463,6 +1468,7 @@ public abstract class ErrorMessages { public static final TruffleString AGEN_ALREADY_RUNNING = tsLiteral("anext(): asynchronous generator is already running"); public static final TruffleString CORO_ALREADY_AWAITED = tsLiteral("coroutine is being awaited already"); public static final TruffleString ANEXT_INVALID_OBJECT = tsLiteral("'async for' received an invalid object from __anext__: %p"); + public static final TruffleString ASYNCGEN_IGNORED_EXIT = tsLiteral("async generator ignored GeneratorExit"); public static final TruffleString ASYNCGEN_RAISED_ASYNCSTOPITER = tsLiteral("async generator raised StopAsyncIteration"); public static final TruffleString MAXSIZE_SHOULD_BE_INTEGER_OR_NONE = tsLiteral("maxsize should be integer or None"); public static final TruffleString THE_FIRST_ARGUMENT_MUST_BE_CALLABLE = tsLiteral("the first argument must be callable"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java index 1eebdddb6c..565ba7cca7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PConstructAndRaiseNode.java @@ -56,9 +56,9 @@ import com.oracle.graal.python.builtins.objects.ssl.SSLErrorCode; import com.oracle.graal.python.nodes.PConstructAndRaiseNodeGen.LazyNodeGen; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; +import com.oracle.graal.python.runtime.PosixSupport.PosixErrnoException; +import com.oracle.graal.python.runtime.PosixSupport.PosixException; +import com.oracle.graal.python.runtime.PosixSupport.UnsupportedPosixFeatureException; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.formatting.ErrorMessageFormatter; @@ -213,8 +213,8 @@ private static Object[] createOsErrorArgs(OSErrorEnum osErrorEnum) { return new Object[]{osErrorEnum.getNumber(), osErrorEnum.getMessage()}; } - private static Object[] createOsErrorArgs(Exception exception, TruffleString.EqualNode eqNode) { - OSErrorEnum.ErrorAndMessagePair errorAndMessage = OSErrorEnum.fromException(exception, eqNode); + private static Object[] createOsErrorArgs(Exception exception) { + OSErrorEnum.ErrorAndMessagePair errorAndMessage = OSErrorEnum.fromException(exception); return new Object[]{errorAndMessage.oserror.getNumber(), errorAndMessage.message}; } @@ -230,8 +230,8 @@ public final PException raiseOSError(Frame frame, OSErrorEnum osErrorEnum, Truff return raiseOSErrorInternal(frame, createOsErrorArgs(osErrorEnum, filename)); } - public final PException raiseOSError(Frame frame, Exception exception, TruffleString.EqualNode eqNode) { - return raiseOSErrorInternal(frame, createOsErrorArgs(exception, eqNode)); + public final PException raiseOSError(Frame frame, Exception exception) { + return raiseOSErrorInternal(frame, createOsErrorArgs(exception)); } public final PException raiseOSError(Frame frame, OSErrorEnum osErrorEnum, Exception exception) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java index 2f2a5daa95..f86db3fc36 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/PGuards.java @@ -309,6 +309,10 @@ public static boolean isBuiltinPInt(PInt obj) { return obj.getPythonClass() == PythonBuiltinClassType.PInt; } + public static boolean isBuiltinPFloat(PFloat obj) { + return obj.getPythonClass() == PythonBuiltinClassType.PFloat; + } + public static boolean isPString(Object obj) { return obj instanceof PString; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java index e4f633836a..3e670fc2e2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/CreateArgumentsNode.java @@ -86,6 +86,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -286,6 +287,7 @@ static PException doUncached(Object[] pArguments, Object callable, Signature sig kwonly_given += 1; } } + LoopNode.reportLoopCount(inliningTarget, co_kwonlyargcount); boolean forgotSelf = methodcall && avail + 1 == co_argcount && (signature.getParameterIds().length == 0 || !equalNode.execute(signature.getParameterIds()[0], T_SELF, TS_ENCODING)); TruffleString name = getName(callable, signature); throw raiseTooManyArguments(inliningTarget, name, co_argcount - adjustCount, ndefaults, avail - adjustCount, forgotSelf, kwonly_given, raise); @@ -544,6 +546,7 @@ static void applyUncached(Object callee, Signature calleeSignature, Object[] pAr lastWrongKeyword = name; } } + LoopNode.reportLoopCount(inliningTarget, kwLen); storeKeywordsOrRaise(callee, pArguments, kwargsIndex, unusedKeywords, k, additionalKwds, lastWrongKeyword, posArgOnlyPassedAsKeywordNames, inliningTarget, posArgOnlyPassedAsKeywordProfile, raise, calleeSignature); } @@ -726,6 +729,7 @@ static void doUncached(Object callable, Signature signature, Object[] pArguments missingNames[missingCnt++] = signature.getParameterIds()[i]; } } + LoopNode.reportLoopCount(inliningTarget, missingNames.length); if (missingProfile.profile(inliningTarget, missingCnt > 0)) { throw raiseMissing(inliningTarget, callable, missingNames, missingCnt, toTruffleStringUncached("positional"), raise, signature); } @@ -804,6 +808,7 @@ static void doUncached(Object callable, Object[] pArguments, Signature signature missingNames[missingCnt++] = kwname; } } + LoopNode.reportLoopCount(inliningTarget, missingNames.length); if (missingProfile.profile(inliningTarget, missingCnt > 0)) { throw raiseMissing(inliningTarget, callable, missingNames, missingCnt, toTruffleStringUncached("keyword-only"), raise, signature); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java index 88b789d1c7..bc1e7a69a7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/ExecutePositionalStarargsNode.java @@ -72,6 +72,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @ImportStatic(PythonOptions.class) @@ -141,6 +142,7 @@ static Object[] starargs(VirtualFrame frame, Object object, Object next = nextNode.execute(frame, inliningTarget, iterator); internalStorage.add(next); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, internalStorage.size()); return internalStorage.toArray(new Object[0]); } } @@ -178,6 +180,7 @@ static Object[] doIt(Node inliningTarget, HashingStorage storage, assert hasNext; args[i] = iteratorKey.execute(inliningTarget, storage, it); } + LoopNode.reportLoopCount(inliningTarget, args.length); return args; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java index 33dda2c045..bda1effcfc 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java @@ -75,6 +75,7 @@ import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -188,6 +189,7 @@ static Object generic(Object type, Object objectType, TruffleString key, while (i < mro.length && !isSameTypeNode.execute(inliningTarget, type, mro[i])) { i++; } + LoopNode.reportLoopCount(inliningTarget, i); if (i + 1 >= mro.length) { return NO_MRO_SUFFIX; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java index 375f0f9eaf..89716be70a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/builtins/TupleNodes.java @@ -52,12 +52,14 @@ import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.CreateStorageFromIteratorNode; import com.oracle.graal.python.builtins.objects.iterator.IteratorNodes; import com.oracle.graal.python.builtins.objects.list.PList; +import com.oracle.graal.python.builtins.objects.range.PIntRange; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.lib.PyObjectGetIter; import com.oracle.graal.python.lib.PyTupleCheckNode; import com.oracle.graal.python.nodes.PGuards; import com.oracle.graal.python.nodes.PNodeWithContext; import com.oracle.graal.python.runtime.object.PFactory; +import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.NativeObjectSequenceStorage; import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; @@ -73,6 +75,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.LoopNode; public abstract class TupleNodes { @@ -101,6 +104,23 @@ static PTuple list(PList iterable, return PFactory.createTuple(language, copyNode.execute(inliningTarget, iterable.getSequenceStorage())); } + @Specialization + static PTuple range(PIntRange range, + @Bind Node inliningTarget, + @Bind PythonLanguage language) { + int start = range.getIntStart(); + int step = range.getIntStep(); + int len = range.getIntLength(); + int[] array = new int[len]; + int value = start; + for (int i = 0; i < len; i++) { + array[i] = value; + value += step; + } + LoopNode.reportLoopCount(inliningTarget, len); + return PFactory.createTuple(language, new IntSequenceStorage(array)); + } + @Specialization(guards = "isNativeTuple(iterable)") static PTuple nativeTuple(PythonAbstractNativeObject iterable, @Bind Node inliningTarget, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java index d03f0d28c0..4b36baf96a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode/ImportStarNode.java @@ -62,6 +62,7 @@ import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -108,6 +109,7 @@ void doImport(VirtualFrame frame, TruffleString moduleName, int level, TruffleString name = TruffleString.fromJavaStringUncached(attrName, TS_ENCODING); setItemNode.execute(frame, inliningTarget, locals, name, attr); } + LoopNode.reportLoopCount(inliningTarget, Math.max(0, len)); } catch (UnknownIdentifierException | UnsupportedMessageException | InvalidArrayIndexException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new IllegalStateException(e); @@ -116,10 +118,14 @@ void doImport(VirtualFrame frame, TruffleString moduleName, int level, try { Object attrAll = getAttrNode.execute(frame, inliningTarget, importedModule, T___ALL__); int n = sizeNode.execute(frame, inliningTarget, attrAll); - for (int i = 0; i < n; i++) { - Object attrName = getItemNode.execute(frame, inliningTarget, attrAll, i); - writeAttributeToLocals(frame, inliningTarget, moduleName, (PythonModule) importedModule, locals, attrName, true, castToTruffleStringNode, codePointLengthNode, - codePointAtIndexNode, getAttrNode, setItemNode); + try { + for (int i = 0; i < n; i++) { + Object attrName = getItemNode.execute(frame, inliningTarget, attrAll, i); + writeAttributeToLocals(frame, inliningTarget, moduleName, (PythonModule) importedModule, locals, attrName, true, castToTruffleStringNode, codePointLengthNode, + codePointAtIndexNode, getAttrNode, setItemNode); + } + } finally { + LoopNode.reportLoopCount(inliningTarget, n); } } catch (PException e) { e.expectAttributeError(inliningTarget, isAttributeErrorProfile); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java index 997fd78c0f..d25e3fca4f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java @@ -325,6 +325,7 @@ import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.SlowPathException; @@ -3947,6 +3948,7 @@ public static Object[] doUnpackIterable(VirtualFrame virtualFrame, Object collec Object item = getNextNode.execute(virtualFrame, inliningTarget, iterator); result.add(item); } catch (IteratorExhausted e) { + LoopNode.reportLoopCount(inliningTarget, result.size()); return result.toArray(new Object[0]); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java index 607266d01c..e5ff5b774c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/SequenceFromArrayNode.java @@ -143,7 +143,7 @@ SequenceStorage createSequenceStorage(Object[] objectElements, int length) { private SequenceStorage initialize(Object[] objectElements) { SequenceStorage storage; try { - storage = SequenceStorageFactory.createStorage(objectElements); + storage = SequenceStorageFactory.createStorage(this, objectElements); type = storage.getElementType(); } catch (Throwable t) { // we do not want to repeatedly deopt if a value execution @@ -189,7 +189,7 @@ public abstract static class ListFromArrayNode extends SequenceFromArrayNode imp private static final ListFromArrayNode UNCACHED = new ListFromArrayNode() { @Override public PList execute(PythonLanguage language, Object[] elements) { - return PFactory.createList(language, SequenceStorageFactory.createStorage(elements)); + return PFactory.createList(language, SequenceStorageFactory.createStorage(this, elements)); } }; @@ -252,7 +252,7 @@ public abstract static class TupleFromArrayNode extends SequenceFromArrayNode { private static final TupleFromArrayNode UNCACHED = new TupleFromArrayNode() { @Override public PTuple execute(PythonLanguage language, Object[] elements) { - return PFactory.createTuple(language, SequenceStorageFactory.createStorage(elements)); + return PFactory.createTuple(language, SequenceStorageFactory.createStorage(this, elements)); } }; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java index 3260807424..d3ba3dac71 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -62,6 +62,7 @@ import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @GenerateUncached @@ -133,11 +134,13 @@ static boolean doSubclass(VirtualFrame frame, @SuppressWarnings("unused") Object } private static boolean loopUnexploded(VirtualFrame frame, Object cachedCls, AbstractObjectIsSubclassNode isSubclassNode, Object[] basesAry, int depth) { - for (Object baseCls : basesAry) { - if (isSubclassNode.executeInternal(frame, baseCls, cachedCls, depth + 1)) { + for (int i = 0; i < basesAry.length; i++) { + if (isSubclassNode.executeInternal(frame, basesAry[i], cachedCls, depth + 1)) { + LoopNode.reportLoopCount(isSubclassNode, i); return true; } } + LoopNode.reportLoopCount(isSubclassNode, basesAry.length); return false; } @@ -194,11 +197,14 @@ private static boolean doGeneric(VirtualFrame frame, Node inliningTarget, Object return false; } - for (Object baseCls : getObjectArrayNode.execute(inliningTarget, bases)) { - if (isSubclassNode.executeInternal(frame, baseCls, cls, depth + 1)) { + Object[] basesArray = getObjectArrayNode.execute(inliningTarget, bases); + for (int i = 0; i < basesArray.length; i++) { + if (isSubclassNode.executeInternal(frame, basesArray[i], cls, depth + 1)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, basesArray.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java index 563e9a35fd..53ec418b54 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/IsSubtypeNode.java @@ -64,6 +64,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -304,11 +305,14 @@ static boolean issubTypeGeneric(Object derived, Object cls, if (builtinClassIsSubtypeProfile.profile(inliningTarget, isBuiltinClass(derived) && !isBuiltinClass(cls))) { return false; } - for (PythonAbstractClass n : getMro.execute(inliningTarget, derived).getInternalClassArray()) { - if (isSameType(inliningTarget, isSameTypeNode, n, cls)) { + PythonAbstractClass[] mro = getMro.execute(inliningTarget, derived).getInternalClassArray(); + for (int i = 0; i < mro.length; i++) { + if (isSameType(inliningTarget, isSameTypeNode, mro[i], cls)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, mro.length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java index 8babbe6225..b94d8fffd8 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/EncapsulateExceptionGroupNode.java @@ -60,6 +60,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -111,6 +112,7 @@ public static Object matchExceptions(VirtualFrame frame, exceptionGroupList.add(exceptionObj); } } + LoopNode.reportLoopCount(inliningTarget, exceptionGroup.getExceptions().length); } else { exceptionGroup.setTraceback(exceptionOrigUnreified.getTraceback()); return PException.fromExceptionInfo(exceptionGroup, PythonOptions.isPExceptionWithJavaStacktrace(language)); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java index 44593245aa..f17f8a059b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/ExceptMatchNode.java @@ -67,6 +67,7 @@ import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; @ImportStatic(PGuards.class) @@ -138,9 +139,11 @@ public static boolean matchTuple(Object e, Object clause, for (int i = 0; i < length; i++) { Object clauseType = getItemNode.execute(inliningTarget, storage, i); if (recursiveNode.executeMatch(e, clauseType)) { + LoopNode.reportLoopCount(inliningTarget, i); return true; } } + LoopNode.reportLoopCount(inliningTarget, length); return false; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java index a3461128c3..7ef541a90f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/HandleExceptionsInHandlerNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -63,6 +63,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; @@ -118,6 +119,7 @@ public static Object addToAcc( for (Object exc : exceptionGroupAcc.getExceptions()) { exceptionGroupsInAcc.add(exc); } + LoopNode.reportLoopCount(inliningTarget, exceptionGroupAcc.getExceptions().length); if (clause == PNone.NONE) { // uncaught grouped exceptions should be bundled together with @@ -156,6 +158,7 @@ public static Object addToAcc( for (Object exc : exceptionGroupAcc.getExceptions()) { exceptionGroupsInAcc.add(exc); } + LoopNode.reportLoopCount(inliningTarget, exceptionGroupAcc.getExceptions().length); exceptionGroupsInAcc.add(exceptionToAdd.getUnreifiedException()); outerExceptionGroup = (PBaseExceptionGroup) deriveExceptionGroup.execute( frame, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java index 3c2f86889a..ce94b8dc4c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/GetFrameLocalsNode.java @@ -61,6 +61,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedIntValueProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -141,6 +142,7 @@ PDict doIt(BytecodeFrame locals, storage = setItem.execute(inliningTarget, storage, name, value); } } + LoopNode.reportLoopCount(inliningTarget, varCount); return PFactory.createDict(language, storage); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java index 212c1cde89..dbab409377 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/statement/AbstractImportNode.java @@ -95,6 +95,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -577,6 +578,7 @@ TruffleString resolveName(VirtualFrame frame, TruffleString name, PDict globals, } } + LoopNode.reportLoopCount(inliningTarget, (int) Math.max(0L, (long) level - 1)); TruffleString base = substringNode.execute(pkgString, 0, lastDotIdx, TS_ENCODING, true); if (name.isEmpty()) { return base; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java new file mode 100644 index 0000000000..ec910f7a8c --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/util/PosixSupportNodes.java @@ -0,0 +1,554 @@ +/* + * Copyright (c) 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 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.nodes.util; + +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeDecodeError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.UnicodeEncodeError; +import static com.oracle.graal.python.util.PythonUtils.SURROGATE_CODE_POINT_SET; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_16LE; +import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_8; + +import java.nio.charset.StandardCharsets; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.annotations.PythonOS; +import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; +import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; +import com.oracle.graal.python.nodes.PNodeWithContext; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.call.CallNode; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreateCStringFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreatePathFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.CreateWideStringFromStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.GetCStringAsStringNodeGen; +import com.oracle.graal.python.nodes.util.PosixSupportNodesFactory.GetPathAsStringNodeGen; +import com.oracle.graal.python.runtime.EmulatedPosixSupport; +import com.oracle.graal.python.runtime.LoggingPosixSupport; +import com.oracle.graal.python.runtime.NativePosixSupport; +import com.oracle.graal.python.runtime.PosixSupport; +import com.oracle.graal.python.runtime.PosixSupport.Buffer; +import com.oracle.graal.python.runtime.PreInitPosixSupport; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Cached.Shared; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.GenerateUncached; +import com.oracle.truffle.api.dsl.Idempotent; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.AbstractTruffleString; +import com.oracle.truffle.api.strings.TranscodingErrorHandler; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.strings.TruffleString.FromByteArrayNode; +import com.oracle.truffle.api.strings.TruffleString.IsValidNode; +import com.oracle.truffle.api.strings.TruffleString.SwitchEncodingNode; + +/** + * Conversions at the boundary between Python strings and the representation used by a POSIX + * backend. Keeping these operations here is important: POSIX support methods can then exchange + * only their backend-native representations and do not need to materialize TruffleStrings. + */ +public final class PosixSupportNodes { + + private PosixSupportNodes() { + } + + @TruffleBoundary + private static String newStringFromUTF8(byte[] utf8Bytes) { + return new String(utf8Bytes, StandardCharsets.UTF_8); + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) + public abstract static class CreatePathFromStringNode extends PNodeWithContext { + public abstract Object execute(Frame frame, Node inliningTarget, PosixSupport posixSupport, TruffleString path); + + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString path) { + return CreatePathFromStringNodeGen.getUncached().execute(null, null, posixSupport, path); + } + + @Specialization(guards = "isWindows()") + static Object doNativeWindows(@SuppressWarnings("unused") Frame frame, @SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, TruffleString path, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); + } + + @Specialization(guards = "!isWindows()") + static Object doNativePosix(Frame frame, Node inliningTarget, NativePosixSupport posixSupport, TruffleString path, + @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + return posixSupport.createRawPath(encodeFSDefaultNode.execute(frame, inliningTarget, path), false); + } + + @Specialization(guards = "isWindows()") + static Object doEmulatedWindows(@SuppressWarnings("unused") Frame frame, @SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString path, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawPath(toJavaStringNode.execute(path)); + } + + @Specialization(guards = "!isWindows()") + static Object doEmulatedPosix(Frame frame, Node inliningTarget, EmulatedPosixSupport posixSupport, TruffleString path, + @Shared @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { + String javaPath = PosixSupportNodes.newStringFromUTF8(encodeFSDefaultNode.execute(frame, inliningTarget, path)); + return posixSupport.createRawPath(javaPath); + } + + @Specialization + static Object doLogging(Frame frame, Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString path, + @Shared @Cached(inline = false) CreatePathFromStringNode delegateNode) { + posixSupport.logConversionEnter("createPathFromString", path); + return posixSupport.logConversionExit("createPathFromString", delegateNode.execute(frame, inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Object doPreInit(Frame frame, Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString path, + @Shared @Cached(inline = false) CreatePathFromStringNode delegateNode) { + return delegateNode.execute(frame, inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) + public abstract static class CreatePathFromBytesNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, byte[] path); + + @Specialization(guards = "!isWindows()") + static Object doNativePosix(@SuppressWarnings("unused") Node inliningTarget, NativePosixSupport posixSupport, byte[] path) { + return posixSupport.createRawPath(path, false); + } + + @Specialization(guards = "isWindows()") + static Object doNativeWindows(Node inliningTarget, NativePosixSupport posixSupport, byte[] path, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString utf8 = fromByteArrayNode.execute(path, UTF_8, true); + TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); + return posixSupport.createRawPath(copyToByteArrayNode.execute(utf16, UTF_16LE), true); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, byte[] path) { + return posixSupport.createRawPath(PosixSupportNodes.newStringFromUTF8(path)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, byte[] path, + @Shared @Cached(inline = false) CreatePathFromBytesNode delegateNode) { + posixSupport.logConversionEnter("createPathFromBytes", path); + return posixSupport.logConversionExit("createPathFromBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, byte[] path, + @Shared @Cached(inline = false) CreatePathFromBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) + public abstract static class GetPathAsStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object path); + + @TruffleBoundary + public static TruffleString executeUncached(PosixSupport posixSupport, Object path) { + return GetPathAsStringNodeGen.getUncached().execute(null, posixSupport, path); + } + + @Specialization(guards = "isWindows()") + static TruffleString doNativeWindows(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Shared @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Shared @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + byte[] data = posixSupport.getRawPathData(path); + return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, + TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + } + + @Specialization(guards = "!isWindows()") + static TruffleString doNativePosix(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Shared @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Shared @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.IsValidNode isValidNode) { + byte[] data = posixSupport.getRawPathData(path); + return decodeFilesystemString(data, data.length, fromByteArrayNode, switchEncodingNode, isValidNode); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, EmulatedPosixSupport posixSupport, Object path, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(posixSupport.getRawPath(path), TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsStringNode delegateNode) { + posixSupport.logConversionEnter("getPathAsString", path); + return posixSupport.logConversionExit("getPathAsString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + @ImportStatic(PosixSupportNodes.class) + public abstract static class GetPathAsBytesNode extends PNodeWithContext { + public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object path); + + @Specialization(guards = "!isWindows()") + static Buffer doNativePosix(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path) { + return Buffer.wrap(posixSupport.getRawPathData(path)); + } + + @Specialization(guards = "isWindows()") + static Buffer doNativeWindows(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object path, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + byte[] data = posixSupport.getRawPathData(path); + TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); + TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); + } + + @Specialization + @TruffleBoundary + static Buffer doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, Object path) { + return Buffer.wrap(posixSupport.getRawPath(path).getBytes(StandardCharsets.UTF_8)); + } + + @Specialization + static Buffer doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsBytesNode delegateNode) { + posixSupport.logConversionEnter("getPathAsBytes", path); + return posixSupport.logConversionExit("getPathAsBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), path)); + } + + @Specialization + static Buffer doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object path, + @Shared @Cached(inline = false) GetPathAsBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), path); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreateCStringFromStringNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString string) { + return CreateCStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + @Specialization + static Object doNative(Node inliningTarget, NativePosixSupport posixSupport, TruffleString string, + @Cached TruffleString.IsValidNode isValidNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + return posixSupport.createCStringFromBytes(encodeStrictUtf8(inliningTarget, string, isValidNode, switchEncodingNode, copyToByteArrayNode)); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString string, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawCString(toJavaStringNode.execute(string)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateCStringFromStringNode delegateNode) { + posixSupport.logConversionEnter("createCStringFromString", string); + return posixSupport.logConversionExit("createCStringFromString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateCStringFromStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class CreateWideStringFromStringNode extends PNodeWithContext { + public abstract Object execute(Node inliningTarget, PosixSupport posixSupport, TruffleString string); + + @TruffleBoundary + public static Object executeUncached(PosixSupport posixSupport, TruffleString string) { + return CreateWideStringFromStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + @Specialization + static Object doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, TruffleString string, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + TruffleString utf16 = switchEncodingNode.execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return posixSupport.createRawWideString(copyToByteArrayNode.execute(utf16, UTF_16LE)); + } + + @Specialization + static Object doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, TruffleString string, + @Cached TruffleString.ToJavaStringNode toJavaStringNode) { + return posixSupport.createRawWideString(toJavaStringNode.execute(string)); + } + + @Specialization + static Object doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateWideStringFromStringNode delegateNode) { + posixSupport.logConversionEnter("createWideStringFromString", string); + return posixSupport.logConversionExit("createWideStringFromString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Object doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, TruffleString string, + @Shared @Cached(inline = false) CreateWideStringFromStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetCStringAsStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object string); + + @TruffleBoundary + public static TruffleString executeUncached(PosixSupport posixSupport, Object string) { + return GetCStringAsStringNodeGen.getUncached().execute(null, posixSupport, string); + } + + @Specialization + static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object string, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + byte[] data = posixSupport.getRawStringData(string); + if (posixSupport.isWideString(string)) { + return switchEncodingNode.execute(fromByteArrayNode.execute(data, UTF_16LE, true), TS_ENCODING, + TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + } + return switchEncodingNode.execute(fromByteArrayNode.execute(data, 0, posixSupport.getRawStringLength(string), UTF_8, true), TS_ENCODING); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, EmulatedPosixSupport posixSupport, Object string, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(posixSupport.getRawCString(string), TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsStringNode delegateNode) { + posixSupport.logConversionEnter("getCStringAsString", string); + return posixSupport.logConversionExit("getCStringAsString", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class GetCStringAsBytesNode extends PNodeWithContext { + public abstract Buffer execute(Node inliningTarget, PosixSupport posixSupport, Object string); + + @Specialization(guards = "!posixSupport.isWideString(string)") + static Buffer doNativeNarrow(@SuppressWarnings("unused") Node inliningTarget, + @SuppressWarnings("unused") NativePosixSupport posixSupport, Object string) { + return (Buffer) string; + } + + @Specialization(guards = "posixSupport.isWideString(string)") + static Buffer doNativeWide(@SuppressWarnings("unused") Node inliningTarget, + NativePosixSupport posixSupport, Object string, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + byte[] data = posixSupport.getRawStringData(string); + TruffleString utf16 = fromByteArrayNode.execute(data, UTF_16LE, true); + TruffleString utf8 = switchEncodingNode.execute(utf16, UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); + return Buffer.wrap(copyToByteArrayNode.execute(utf8, UTF_8)); + } + + @Specialization + @TruffleBoundary + static Buffer doEmulated(@SuppressWarnings("unused") Node inliningTarget, + EmulatedPosixSupport posixSupport, Object string) { + return Buffer.wrap(posixSupport.getRawCString(string).getBytes(StandardCharsets.UTF_8)); + } + + @Specialization + static Buffer doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsBytesNode delegateNode) { + posixSupport.logConversionEnter("getCStringAsBytes", string); + return posixSupport.logConversionExit("getCStringAsBytes", delegateNode.execute(inliningTarget, posixSupport.getDelegate(), string)); + } + + @Specialization + static Buffer doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object string, + @Shared @Cached(inline = false) GetCStringAsBytesNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), string); + } + } + + /** Decodes a native byte field using the filesystem encoding and surrogateescape on Unix. */ + @GenerateUncached + @GenerateInline(inlineByDefault = true) + public abstract static class DecodeFilesystemStringNode extends PNodeWithContext { + public abstract TruffleString execute(Node inliningTarget, PosixSupport posixSupport, Object bytes); + + @Specialization + static TruffleString doNative(@SuppressWarnings("unused") Node inliningTarget, @SuppressWarnings("unused") NativePosixSupport posixSupport, + Buffer bytes, + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode, + @Cached TruffleString.IsValidNode isValidNode) { + return decodeFilesystemString(bytes.data, (int) bytes.length, fromByteArrayNode, switchEncodingNode, isValidNode); + } + + @Specialization + static TruffleString doEmulated(@SuppressWarnings("unused") Node inliningTarget, + @SuppressWarnings("unused") EmulatedPosixSupport posixSupport, String bytes, + @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + return fromJavaStringNode.execute(bytes, TS_ENCODING); + } + + @Specialization + static TruffleString doLogging(Node inliningTarget, LoggingPosixSupport posixSupport, Object bytes, + @Shared @Cached(inline = false) DecodeFilesystemStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getDelegate(), bytes); + } + + @Specialization + static TruffleString doPreInit(Node inliningTarget, PreInitPosixSupport posixSupport, Object bytes, + @Shared @Cached(inline = false) DecodeFilesystemStringNode delegateNode) { + return delegateNode.execute(inliningTarget, posixSupport.getCurrentBackend(), bytes); + } + } + + @Idempotent + static boolean isWindows() { + return PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32; + } + + private static byte[] encodeStrictUtf8(Node inliningTarget, TruffleString string, TruffleString.IsValidNode isValidNode, + TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + if (!isValidNode.execute(string, TS_ENCODING)) { + throw raiseSurrogatesEncodeError(inliningTarget, string); + } + TruffleString utf8 = switchEncodingNode.execute(string, UTF_8); + return copyToByteArrayNode.execute(utf8, UTF_8); + } + + @TruffleBoundary + private static PException raiseSurrogatesEncodeError(Node node, TruffleString string) { + int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(string, 0, string.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); + int start = byteIndex < 0 ? 0 : byteIndex / 4; + int length = string.codePointLengthUncached(TS_ENCODING); + int end = Math.min(start + 1, length); + while (end < length) { + int codePoint = string.codePointAtIndexUncached(end, TS_ENCODING); + if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { + break; + } + end++; + } + Object exception = CallNode.executeUncached(UnicodeEncodeError, TruffleString.fromJavaStringUncached("utf-8", TS_ENCODING), string, start, end, + TruffleString.fromJavaStringUncached("surrogates not allowed", TS_ENCODING)); + return PRaiseNode.raiseExceptionObjectStatic(node, exception); + } + + private static TruffleString decodeFilesystemString(byte[] data, int length, + FromByteArrayNode fromByteArrayNode, SwitchEncodingNode switchEncodingNode, + IsValidNode isValidNode) { + TruffleString utf8 = fromByteArrayNode.execute(data, 0, length, UTF_8, true); + if (isValidNode.execute(utf8, UTF_8)) { + return switchEncodingNode.execute(utf8, TS_ENCODING); + } + TranscodingErrorHandler handler = isWindows() ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; + return switchEncodingNode.execute(utf8, TS_ENCODING, handler); + } + + private static TranscodingErrorHandler windowsPathDecodeErrorHandler(Node inliningTarget, byte[] input) { + return (AbstractTruffleString sourceString, int byteIndex, int estimatedByteLength, TruffleString.Encoding sourceEncoding, + TruffleString.Encoding targetEncoding) -> { + if (byteIndex + 2 < input.length && (input[byteIndex] & 0xff) == 0xed && + (input[byteIndex + 1] & 0xe0) == 0xa0 && (input[byteIndex + 2] & 0xc0) == 0x80) { + int codePoint = ((input[byteIndex] & 0x0f) << 12) | ((input[byteIndex + 1] & 0x3f) << 6) | (input[byteIndex + 2] & 0x3f); + return new TranscodingErrorHandler.ReplacementString(TruffleString.fromCodePointUncached(codePoint, UTF_16LE, true), 3); + } + Object exception = CallNode.executeUncached(UnicodeDecodeError, + TruffleString.fromJavaStringUncached("utf-8", TS_ENCODING), + com.oracle.graal.python.runtime.object.PFactory.createBytes(PythonLanguage.get(inliningTarget), input), byteIndex, + Math.min(input.length, byteIndex + Math.max(1, estimatedByteLength)), + TruffleString.fromJavaStringUncached("invalid UTF-8 path", TS_ENCODING)); + throw PRaiseNode.raiseExceptionObjectStatic(inliningTarget, exception); + }; + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java index 92241c2cf8..119db224e2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java @@ -128,7 +128,6 @@ import static com.oracle.graal.python.runtime.PosixConstants.W_OK; import static com.oracle.graal.python.runtime.PosixConstants.X_OK; import static com.oracle.graal.python.util.PythonUtils.EMPTY_INT_ARRAY; -import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import static com.oracle.truffle.api.CompilerAsserts.neverPartOfCompilation; @@ -227,35 +226,13 @@ import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.OperationWouldBlockException; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; import com.oracle.graal.python.nodes.ErrorMessages; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.ChannelNotSelectableException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.graal.python.runtime.exception.PythonExitException; import com.oracle.graal.python.util.FileDeleteShutdownHook; import com.oracle.graal.python.util.IPAddressUtil; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleFile; import com.oracle.truffle.api.TruffleFile.Attributes; @@ -264,23 +241,10 @@ import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.TruffleSafepoint; -import com.oracle.truffle.api.dsl.Bind; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; -import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.GenerateCached; -import com.oracle.truffle.api.dsl.GenerateInline; -import com.oracle.truffle.api.dsl.GenerateUncached; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.io.TruffleProcessBuilder; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.library.ExportMessage.Ignore; import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; import com.sun.security.auth.UnixNumericGroupPrincipal; import com.sun.security.auth.module.UnixSystem; @@ -312,10 +276,21 @@ *
  • {@code select} supports only network sockets, but not regular files.
  • * */ -@ExportLibrary(PosixSupportLibrary.class) -@SuppressWarnings("unused") public final class EmulatedPosixSupport extends PosixResources { + public static final class EmulatedPwdResult extends PwdResult { + public final String name; + public final String dir; + public final String shell; + + public EmulatedPwdResult(String name, long uid, long gid, String dir, String shell) { + super(uid, gid); + this.name = name; + this.dir = dir; + this.shell = shell; + } + } + private static final int MAX_READ = Integer.MAX_VALUE / 2; private static final PosixFilePermission[][] otherBitsToPermission = new PosixFilePermission[][]{ @@ -348,10 +323,12 @@ public final class EmulatedPosixSupport extends PosixResources { new PosixFilePermission[]{PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE}, new PosixFilePermission[]{PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE}, }; - private static final TruffleString T_BIN_SH = tsLiteral("/bin/sh"); - private static final TruffleString T_DEV_TTY = tsLiteral("/dev/tty"); + private static final String T_DEV_TTY = "/dev/tty"; + private static final LinkOption[] NO_LINK_OPTIONS = new LinkOption[0]; private final ConcurrentHashMap environ = new ConcurrentHashMap<>(); + private long pid; + private boolean pidInitialized; private int currentUmask = 0022; private boolean hasDefaultUmask = true; private final boolean withoutIOSocket; @@ -368,8 +345,8 @@ public EmulatedPosixSupport(PythonContext context) { withoutIOSocket = !context.getContext().getEnv().isSocketIOAllowed(); } - @TruffleBoundary static UnsupportedPosixFeatureException createUnsupportedFeature(String message) { + CompilerAsserts.neverPartOfCompilation(); // TODO should have a link to some doc that tells you what to do about it return new UnsupportedPosixFeatureException("Feature not supported on 'java' POSIX backend: " + message); } @@ -380,43 +357,49 @@ public void setEnv(Env env) { if (!env.isPreInitialization()) { environ.putAll(env.getEnvironment()); } + pidInitialized = false; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public TruffleString getBackend() { return T_JAVA; } - @ExportMessage - public static class Getpid { - - private static final TruffleString T_PROC_SELF_STAT = tsLiteral("/proc/self/stat"); - - @Specialization(rewriteOn = Exception.class) - @TruffleBoundary - static long getPid(EmulatedPosixSupport receiver) throws Exception { + @TruffleBoundary + private long determinePid() { + long pid; + try { if (ImageInfo.inImageRuntimeCode()) { - return ProcessProperties.getProcessID(); + pid = ProcessProperties.getProcessID(); + } else { + pid = ProcessHandle.current().pid(); } - TruffleFile statFile = receiver.context.getPublicTruffleFileRelaxed(T_PROC_SELF_STAT); - return Long.parseLong(new String(statFile.readAllBytes()).trim().split(" ")[0]); - } - - @Specialization(replaces = "getPid") - @TruffleBoundary - static long getPidFallback(@SuppressWarnings("unused") EmulatedPosixSupport receiver) { + } catch (Exception e) { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { + // Java 8 compatibility String info = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); - return Long.parseLong(info.split("@")[0]); + pid = Long.parseLong(info.split("@")[0]); } else { - return Long.MAX_VALUE; + pid = Long.MAX_VALUE; } } + this.pid = pid; + this.pidInitialized = true; + return pid; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary + public long getpid() { + if (pidInitialized) { + return pid; + } + return determinePid(); + } + + @Override + @TruffleBoundary public int umask(int umask) { int prev = currentUmask; currentUmask = umask & 00777; @@ -427,22 +410,19 @@ public int umask(int umask) { return umask; } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public TruffleString strerror(int errorCode, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) { + @Override + @TruffleBoundary + public TruffleString strerror(int errorCode) { OSErrorEnum err = OSErrorEnum.fromNumber(errorCode); if (err == null) { - errorBranch.enter(inliningTarget); err = OSErrorEnum.EINVAL; } return err.getMessage(); } - @ExportMessage(name = "close") - public int closeMessage(int fd) throws PosixException { - // TODO: to be replaced with super.close once the super class is merged with this class + @Override + @TruffleBoundary + public int close(int fd) throws PosixException { try { if (!removeFD(fd)) { throw posixException(OSErrorEnum.EBADF); @@ -453,24 +433,16 @@ public int closeMessage(int fd) throws PosixException { } } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public int openat(int dirFd, Object path, int flags, int mode, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, eqNode, toJavaStringNode); + @Override + @TruffleBoundary + public int openat(int dirFd, Object path, int flags, int mode) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set options = flagsToOptions(flags); - FileAttribute> attributes = modeToAttributes(mode & ~currentUmask); + FileAttribute> attributes = PosixFilePermissions.asFileAttribute(modeToPosixFilePermissions(mode & ~currentUmask)); try { return openTruffleFile(file, options, attributes); } catch (Exception e) { - errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } @@ -496,45 +468,43 @@ private int openTruffleFile(TruffleFile truffleFile, Set opt return open(file, fc); } - @ExportMessage - public long write(int fd, Buffer data, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public long write(int fd, Buffer data) throws PosixException { Channel channel = getFileChannel(fd); - if (!(channel instanceof WritableByteChannel)) { - errorBranch.enter(inliningTarget); + if (!(channel instanceof WritableByteChannel writableChannel)) { throw posixException(OSErrorEnum.EBADF); } try { - return doWriteOp(data.getByteBuffer(), (WritableByteChannel) channel); + return writableChannel.write(data.getByteBuffer()); } catch (Exception e) { - errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @TruffleBoundary(allowInlining = true) - private static int doWriteOp(ByteBuffer data, WritableByteChannel channel) throws IOException { - return channel.write(data); + @Override + @TruffleBoundary + public int getWindowsConsoleType(int fd) { + return 0; } - @ExportMessage - @SuppressWarnings({"unused", "static-method"}) - public Buffer read(int fd, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public long writeWindowsConsole(int fd, Buffer data) throws PosixException { + return write(fd, data); + } + + @Override + @TruffleBoundary + public Buffer read(int fd, long length) throws PosixException { Channel channel = getFileChannel(fd); - if (!(channel instanceof ReadableByteChannel)) { - errorBranch.enter(inliningTarget); + if (!(channel instanceof ReadableByteChannel readableChannel)) { throw posixException(OSErrorEnum.EBADF); } try { - return readBytesFromChannel((ReadableByteChannel) channel, length); + return readBytesFromChannel(readableChannel, length); } catch (Exception e) { - errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -560,49 +530,52 @@ private static Buffer readBytesFromChannel(ReadableByteChannel channel, long siz } @Override - @ExportMessage + @TruffleBoundary public int dup(int fd) { // TODO: will disappear once the super class is merged with this class return super.dup(fd); } - @ExportMessage - public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public int dup2(int fd, int fd2, @SuppressWarnings("unused") boolean inheritable) throws PosixException { // TODO: will merge with super.dup2 once the super class is merged with this class try { return super.dup2(fd, fd2); } catch (IOException ex) { - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public boolean getInheritable(int fd) { compatibilityIgnored("getting inheritable for file descriptor %d in POSIX emulation layer (not supported, always returns false)", fd); return false; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public void setInheritable(int fd, boolean inheritable) { compatibilityIgnored("setting inheritable '%b' for file descriptor %d in POSIX emulation layer (not supported)", inheritable, fd); } - @ExportMessage + @Override @SuppressWarnings("static-method") + @TruffleBoundary public long getOsfHandle(int fd) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("get_osfhandle"); } - @ExportMessage + @Override @SuppressWarnings("static-method") + @TruffleBoundary public int openOsfHandle(long handle, int flags) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("open_osfhandle"); } - @ExportMessage + @Override + @TruffleBoundary public int setMode(int fd, int mode) throws PosixException { int binary = PosixConstants.O_BINARY.getValueIfDefined(); int text = PosixConstants.O_TEXT.getValueIfDefined(); @@ -616,36 +589,33 @@ public int setMode(int fd, int mode) throws PosixException { return previousMode; } - @ExportMessage - public void msvcrtLocking(int fd, int mode, long nbytes, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } boolean unlock = mode == PosixConstants._LK_UNLCK.getValueIfDefined(); boolean blocking = mode == PosixConstants._LK_LOCK.getValueIfDefined() || mode == PosixConstants._LK_RLCK.getValueIfDefined(); boolean nonBlocking = mode == PosixConstants._LK_NBLCK.getValueIfDefined() || mode == PosixConstants._LK_NBRLCK.getValueIfDefined(); if (!unlock && !blocking && !nonBlocking) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, false, blocking, SEEK_CUR.value, 0, nbytes); } - @ExportMessage(name = "pipe") - public int[] pipeMessage(@Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - // TODO: will merge with super.pipe once the super class is merged with this class + @Override + @TruffleBoundary + public int[] pipe() throws PosixException { try { - return super.pipe(); + return super.pipeResource(); } catch (IOException ex) { - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } - @ExportMessage + @Override @TruffleBoundary public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -733,7 +703,7 @@ public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeva } catch (IllegalBlockingModeException e) { throw posixException(OSErrorEnum.EINVAL); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached())); + throw posixException(OSErrorEnum.fromException(e)); } finally { i = 0; try { @@ -793,8 +763,7 @@ private SelectableChannel getSelectableChannel(int fd) throws PosixException { return (SelectableChannel) ch; } else if (ch instanceof EmulatedDatagramSocket) { return ((EmulatedDatagramSocket) ch).channel; - } else if (ch instanceof EmulatedStreamSocket) { - EmulatedStreamSocket streamSocket = (EmulatedStreamSocket) ch; + } else if (ch instanceof EmulatedStreamSocket streamSocket) { synchronized (streamSocket) { if (streamSocket.clientChannel != null) { return streamSocket.clientChannel; @@ -806,7 +775,7 @@ private SelectableChannel getSelectableChannel(int fd) throws PosixException { throw ChannelNotSelectableException.INSTANCE; } - @ExportMessage + @Override @TruffleBoundary public void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { assert fds.length == events.length && fds.length == revents.length; @@ -874,18 +843,14 @@ private static int pollFlag(PosixConstants.IntConstant constant) { return constant.defined ? constant.getValueIfDefined() : 0; } - @ExportMessage - public long lseek(int fd, long offset, int how, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile noFile, - @Exclusive @Cached InlinedConditionProfile notSeekable, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public long lseek(int fd, long offset, int how) throws PosixException { Channel channel = getFileChannel(fd); - if (noFile.profile(inliningTarget, channel == null)) { + if (channel == null) { throw posixException(OSErrorEnum.EBADF); } - if (notSeekable.profile(inliningTarget, !(channel instanceof SeekableByteChannel))) { + if (!(channel instanceof SeekableByteChannel fc)) { throw posixException(OSErrorEnum.ESPIPE); } if (SEEK_DATA.defined && how == SEEK_DATA.getValueIfDefined()) { @@ -894,13 +859,11 @@ public long lseek(int fd, long offset, int how, if (SEEK_HOLE.defined && how == SEEK_HOLE.getValueIfDefined()) { throw createUnsupportedFeature("SEEK_HOLE"); } - SeekableByteChannel fc = (SeekableByteChannel) channel; long newPos; try { newPos = setPosition(offset, how, fc); } catch (Exception e) { - errorBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } return newPos; } @@ -927,35 +890,28 @@ private static long setPosition(long pos, int how, SeekableByteChannel fc) throw return fc.position(); } - @ExportMessage(name = "ftruncate") - public void ftruncateMessage(int fd, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - // TODO: will merge with super.ftruncate once the super class is merged with this class + @Override + @TruffleBoundary + public void ftruncate(int fd, long length) throws PosixException { Object ret; try { - ret = ftruncate(fd, length); + ret = ftruncateResource(fd, length); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } if (ret == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } } - @ExportMessage - public void truncate(Object path, long length, - @Bind Node inliningTarget, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = getTruffleFile(pathname, eqNode); + @Override + @TruffleBoundary + public void truncate(Object path, long length) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(path)); try { doTruncate(file, length); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -966,20 +922,19 @@ private static void doTruncate(TruffleFile file, long length) throws IOException } } - @ExportMessage(name = "fsync") - public void fsyncMessage(int fd) throws PosixException { - if (!fsync(fd)) { + @Override + @TruffleBoundary + public void fsync(int fd) throws PosixException { + if (!hasFsyncResource(fd)) { throw posixException(OSErrorEnum.ENOENT); } } - @ExportMessage - void flock(int fd, int operation, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void flock(int fd, int operation) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADFD); } boolean unlock = operation == LOCK_UN.value; @@ -987,26 +942,22 @@ void flock(int fd, int operation, boolean exclusive = (operation & LOCK_EX.value) != 0; boolean blocking = (operation & LOCK_NB.value) == 0; if (!unlock && !shared && !exclusive) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, shared, blocking, 0, 0, Long.MAX_VALUE); } - @ExportMessage - void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws PosixException { + @Override + @TruffleBoundary + public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { Channel channel = getFileChannel(fd); if (channel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADFD); } boolean unlock = lockType == F_UNLCK.getValueIfDefined(); boolean shared = lockType == F_RDLCK.getValueIfDefined(); boolean exclusive = lockType == F_WRLCK.getValueIfDefined(); if (!unlock && !shared && !exclusive) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EINVAL); } doLockOperation(fd, channel, unlock, shared, blocking, whence, start, length); @@ -1054,24 +1005,25 @@ private void doLockOperation(int fd, Channel channel, boolean unlock, boolean sh } } } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached())); + throw posixException(OSErrorEnum.fromException(e)); } setFileLock(fd, lock); } } - @ExportMessage + @Override + @TruffleBoundary public boolean getBlocking(int fd) throws PosixException { Channel channel = getChannel(fd); if (channel == null) { throw posixException(OSErrorEnum.EBADF); } - if (channel instanceof EmulatedSocket) { - return getBlocking((EmulatedSocket) channel); + if (channel instanceof EmulatedSocket emulatedSocket) { + return emulatedSocket.isBlocking(); } Channel fileChannel = getFileChannel(fd); - if (fileChannel instanceof SelectableChannel) { - return getBlocking((SelectableChannel) fileChannel); + if (fileChannel instanceof SelectableChannel selectableChannel) { + return selectableChannel.isBlocking(); } if (fileChannel == null) { throw posixException(OSErrorEnum.EBADFD); @@ -1081,34 +1033,21 @@ public boolean getBlocking(int fd) throws PosixException { return true; } + @Override @TruffleBoundary - @Ignore - private static boolean getBlocking(SelectableChannel channel) { - return channel.isBlocking(); - } - - @TruffleBoundary - @Ignore - private static boolean getBlocking(EmulatedSocket socket) { - return socket.isBlocking(); - } - - @ExportMessage - @SuppressWarnings({"static-method", "unused"}) - public void setBlocking(int fd, boolean blocking, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public void setBlocking(int fd, boolean blocking) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("setBlocking was excluded"); } try { Channel channel = getChannel(fd); - if (channel instanceof EmulatedSocket) { - setBlocking((EmulatedSocket) channel, blocking); + if (channel instanceof EmulatedSocket emulatedSocket) { + emulatedSocket.configureBlocking(blocking); return; } Channel fileChannel = getFileChannel(fd); - if (fileChannel instanceof SelectableChannel) { - setBlocking((SelectableChannel) fileChannel, blocking); + if (fileChannel instanceof SelectableChannel selectableChannel) { + selectableChannel.configureBlocking(blocking); } else if (fileChannel != null) { if (blocking) { // Already blocking @@ -1119,25 +1058,14 @@ public void setBlocking(int fd, boolean blocking, } catch (PosixException e) { throw e; } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } // if we reach this point, it's an invalid FD throw posixException(OSErrorEnum.EBADFD); } + @Override @TruffleBoundary - @Ignore - private static void setBlocking(SelectableChannel channel, boolean block) throws IOException { - channel.configureBlocking(block); - } - - @TruffleBoundary - @Ignore - private static void setBlocking(EmulatedSocket socket, boolean block) throws IOException { - socket.configureBlocking(block); - } - - @ExportMessage public int[] getTerminalSize(int fd) throws PosixException { if (getFileChannel(fd) == null) { throw posixException(OSErrorEnum.EBADF); @@ -1145,7 +1073,7 @@ public int[] getTerminalSize(int fd) throws PosixException { return new int[]{context.getOption(PythonOptions.TerminalWidth), context.getOption(PythonOptions.TerminalHeight)}; } - @ExportMessage + @Override @TruffleBoundary public long sysconf(int name) throws PosixException { // Constants derived from POSIX specs or common kernel configs @@ -1175,61 +1103,45 @@ public long sysconf(int name) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage - public long[] fstatat(int dirFd, Object path, boolean followSymlinks, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathname = pathToTruffleString(path, fromJavaStringNode); - TruffleFile f = resolvePath(inliningTarget, dirFd, pathname, defaultDirFdPofile, eqNode, toJavaStringNode); + @Override + @TruffleBoundary + public long[] fstatat(int dirFd, Object path, boolean followSymlinks) throws PosixException { + TruffleFile f = resolvePath(dirFd, pathToJavaString(path)); LinkOption[] linkOptions = getLinkOptions(followSymlinks); try { return fstat(f, linkOptions); } catch (Exception e) { - errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } - @ExportMessage - public long[] fstat(int fd, - @Bind Node inliningTarget, - @Exclusive @Cached InlinedBranchProfile nullPathProfile, - @Exclusive @Cached InlinedBranchProfile errorBranch, - @Exclusive @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + @Override + @TruffleBoundary + public long[] fstat(int fd) throws PosixException { + String path = getFilePath(fd); if (path == null) { - nullPathProfile.enter(inliningTarget); Channel fileChannel = getFileChannel(fd); if (fileChannel == null) { - errorBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EBADF); } return fstatWithoutPath(fileChannel); } - TruffleFile f = getTruffleFile(path, eqNode); + TruffleFile f = getTruffleFile(path); try { - return fstat(f, new LinkOption[0]); + return fstat(f, NO_LINK_OPTIONS); } catch (Exception e) { - errorBranch.enter(inliningTarget); - ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); throw posixException(errAndMsg); } } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public long[] statvfs(Object path) throws PosixException { try { Env env = PythonContext.get(null).getEnv(); - TruffleFile truffleFile = env.getPublicTruffleFile((String) path); + TruffleFile truffleFile = env.getPublicTruffleFile(pathToJavaString(path)); TruffleFile.FileStoreInfo fileStoreInfo = truffleFile.getFileStoreInfo(); long totalSpace, usableSpace, unallocatedSpace, blockSize; @@ -1262,8 +1174,8 @@ public long[] statvfs(Object path) throws PosixException { } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public long[] fstatvfs(int fd) throws PosixException { String path = getFilePath(fd); @@ -1423,9 +1335,13 @@ private static long[] setTimestamps(Attributes attributes, TruffleFile.Attribute FileTime atime = attributes.get(LAST_ACCESS_TIME); FileTime mtime = attributes.get(LAST_MODIFIED_TIME); FileTime ctime = attributes.get(ctimeDescriptor); - statResult[7] = fileTimeToSeconds(atime); - statResult[8] = fileTimeToSeconds(mtime); - statResult[9] = fileTimeToSeconds(ctime); + assert atime != null; + assert mtime != null; + assert ctime != null; + + statResult[7] = atime.to(TimeUnit.SECONDS); + statResult[8] = mtime.to(TimeUnit.SECONDS); + statResult[9] = ctime.to(TimeUnit.SECONDS); statResult[10] = fileTimeNanoSecondsPart(atime); statResult[11] = fileTimeNanoSecondsPart(mtime); statResult[12] = fileTimeNanoSecondsPart(ctime); @@ -1503,22 +1419,21 @@ private static int posixPermissionsToMode(int inputMode, final Set postpone reopen until readdir() is called dirStream.needsReopen = true; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object dirEntryGetName(Object dirEntry) { TruffleFile file = (TruffleFile) dirEntry; return file.getName(); } - @ExportMessage - @SuppressWarnings("static-method") - public Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { + @Override + @TruffleBoundary + public Object dirEntryGetPath(Object dirEntry, Object scandirPath) { TruffleFile file = (TruffleFile) dirEntry; // Given that scandirPath must have been successfully channeled via opendir, we can assume // that it is a valid path - TruffleFile dir = context.getPublicTruffleFileRelaxed(pathToTruffleString(scandirPath, fromJavaStringNode)); + TruffleFile dir = context.getPublicTruffleFileRelaxed(pathToJavaString(scandirPath)); // We let the filesystem handle the proper concatenation of the two paths return dir.resolve(file.getName()).getPath(); } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") - public long dirEntryGetInode(Object dirEntry, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public long dirEntryGetInode(Object dirEntry) throws PosixException { TruffleFile file = (TruffleFile) dirEntry; try { Attributes attributes = file.getAttributes(Collections.singletonList(UNIX_INODE), LinkOption.NOFOLLOW_LINKS); @@ -1857,13 +1709,12 @@ public long dirEntryGetInode(Object dirEntry, } catch (UnsupportedOperationException e) { return getEmulatedInode(file); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") public int dirEntryGetType(Object dirEntry) { TruffleFile file = (TruffleFile) dirEntry; try { @@ -1883,61 +1734,39 @@ public int dirEntryGetType(Object dirEntry) { return DT_UNKNOWN.value; } - @ExportMessage - public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleString pathStr = pathToTruffleString(path, fromJavaStringNode); - TruffleFile file = resolvePath(inliningTarget, dirFd, pathStr, defaultDirFdPofile, eqNode, toJavaStringNode); - setUTimeNode.execute(inliningTarget, file, timespec, followSymlinks); - } - - @ExportMessage - public void futimens(int fd, long[] timespec, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); - setUTimeNode.execute(inliningTarget, file, timespec, true); - } - - @ExportMessage - public void futimes(int fd, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); - } - - @ExportMessage - public void lutimes(Object filename, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr, eqNode); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), false); - } - - @ExportMessage - public void utimes(Object filename, Timeval[] timeval, - @Bind Node inliningTarget, - @Shared("setUTime") @Cached SetUTimeNode setUTimeNode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString filenameStr = pathToTruffleString(filename, fromJavaStringNode); - TruffleFile file = getTruffleFile(filenameStr, eqNode); - setUTimeNode.execute(inliningTarget, file, timevalToTimespec(timeval), true); + @Override + @TruffleBoundary + public void utimensat(int dirFd, Object path, long[] timespec, boolean followSymlinks) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); + setUTime(file, timespec, followSymlinks); + } + + @Override + @TruffleBoundary + public void futimens(int fd, long[] timespec) throws PosixException { + TruffleFile file = getTruffleFile(getFilePath(fd)); + setUTime(file, timespec, true); + } + + @Override + @TruffleBoundary + public void futimes(int fd, Timeval[] timeval) throws PosixException { + TruffleFile file = getTruffleFile(getFilePath(fd)); + setUTime(file, timevalToTimespec(timeval), true); + } + + @Override + @TruffleBoundary + public void lutimes(Object filename, Timeval[] timeval) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(filename)); + setUTime(file, timevalToTimespec(timeval), false); + } + + @Override + @TruffleBoundary + public void utimes(Object filename, Timeval[] timeval) throws PosixException { + TruffleFile file = getTruffleFile(pathToJavaString(filename)); + setUTime(file, timevalToTimespec(timeval), true); } private static long[] timevalToTimespec(Timeval[] timeval) { @@ -1948,120 +1777,75 @@ private static long[] timevalToTimespec(Timeval[] timeval) { timeval[1].getSeconds(), timeval[1].getMicroseconds() * 1000}; } - @GenerateUncached - @GenerateInline - @GenerateCached(false) - public abstract static class SetUTimeNode extends Node { - abstract void execute(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks) throws PosixException; - - @Specialization(guards = "timespec == null") - static void doCurrentTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - FileTime time = currentFileTime(); - setFileTimes(inliningTarget, followSymlinks, file, time, time, errBranch, eqNode); - } - - @TruffleBoundary - private static FileTime currentFileTime() { - return FileTime.from(Instant.now()); - } - - // the second guard is just so that Truffle does not generate dead code that throws - // UnsupportedSpecializationException.. - @Specialization(guards = {"timespec != null", "file != null"}) - static void doGivenTime(Node inliningTarget, TruffleFile file, long[] timespec, boolean followSymlinks, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - FileTime atime = toFileTime(timespec[0], timespec[1]); - FileTime mtime = toFileTime(timespec[2], timespec[3]); - setFileTimes(inliningTarget, followSymlinks, file, mtime, atime, errBranch, eqNode); + private static void setUTime(TruffleFile file, long[] timespec, boolean followSymlinks) throws PosixException { + CompilerAsserts.neverPartOfCompilation(); + FileTime atime; + FileTime mtime; + if (timespec == null) { + atime = mtime = FileTime.from(Instant.now()); + } else { + atime = toFileTime(timespec[0], timespec[1]); + mtime = toFileTime(timespec[2], timespec[3]); } - - private static void setFileTimes(Node inliningTarget, boolean followSymlinks, TruffleFile file, FileTime mtime, FileTime atime, InlinedBranchProfile errBranch, TruffleString.EqualNode eqNode) - throws PosixException { - try { - file.setLastAccessTime(atime, getLinkOptions(followSymlinks)); - file.setLastModifiedTime(mtime, getLinkOptions(followSymlinks)); - } catch (Exception e) { - errBranch.enter(inliningTarget); - final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e, eqNode); - // setLastAccessTime/setLastModifiedTime and NOFOLLOW_LINKS does not work (at least) - // on OpenJDK8 on Linux and gives ELOOP error. See some explanation in this thread: - // https://stackoverflow.com/questions/17308363/symlink-lastmodifiedtime-in-java-1-7 - if (errAndMsg.oserror == OSErrorEnum.ELOOP && !followSymlinks) { - throw createUnsupportedFeature("utime with 'follow symlinks' flag"); - } - throw posixException(errAndMsg); + try { + file.setLastAccessTime(atime, getLinkOptions(followSymlinks)); + file.setLastModifiedTime(mtime, getLinkOptions(followSymlinks)); + } catch (Exception e) { + final ErrorAndMessagePair errAndMsg = OSErrorEnum.fromException(e); + // setLastAccessTime/setLastModifiedTime and NOFOLLOW_LINKS does not work (at least) + // on OpenJDK8 on Linux and gives ELOOP error. + if (errAndMsg.oserror == OSErrorEnum.ELOOP && !followSymlinks) { + throw createUnsupportedFeature("utime with 'follow symlinks' flag"); } + throw posixException(errAndMsg); } + } - private static FileTime toFileTime(long seconds, long nanos) { - // JDK allows to set only one "time" per one operation, so - // UnixFileAttributeViews#setTimes is setting only one of the mtime/atime but internally - // it needs to call POSIX utime providing both, so it takes the other from fstat, but - // since JDK's fstat wrapper does not support better granularity than seconds, it - // will override nanoseconds component that may have been set by our code already. - // To make this less confusing, we intentionally ignore the nanoseconds component, even - // thought we could set microseconds for one of the mtime/atime (the one that is set - // last) - return FileTime.from(seconds, TimeUnit.SECONDS); - } + private static FileTime toFileTime(long seconds, @SuppressWarnings("unused") long nanos) { + // JDK allows to set only one time per operation, so setting one may round the other to + // seconds. Ignore nanoseconds consistently for both times. + return FileTime.from(seconds, TimeUnit.SECONDS); } - @ExportMessage - public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { + @Override + @TruffleBoundary + public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile oldFile = resolvePath(oldDirFd, pathToJavaString(oldPath)); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { + @Override + @TruffleBoundary + public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { try { - TruffleFile newFile = resolvePath(inliningTarget, newDirFd, pathToTruffleString(newPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile newFile = resolvePath(newDirFd, pathToJavaString(newPath)); if (newFile.isDirectory()) { throw posixException(OSErrorEnum.EISDIR); } - TruffleFile oldFile = resolvePath(inliningTarget, oldDirFd, pathToTruffleString(oldPath, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + TruffleFile oldFile = resolvePath(oldDirFd, pathToJavaString(oldPath)); oldFile.move(newFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { if (effectiveIds) { - errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } - TruffleFile file = null; + TruffleFile file; try { - file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + file = resolvePath(dirFd, pathToJavaString(path)); } catch (PosixException e) { // When the dirFd is invalid descriptor, we just return false, like the real faccessat return false; @@ -2076,12 +1860,11 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, if (!followSymlinks) { // TruffleFile#isExecutable/isReadable/isWriteable does not support LinkOptions, but // that's probably because Java NIO does not support NOFOLLOW_LINKS in permissions check - errBranch.enter(inliningTarget); throw createUnsupportedFeature("faccess with effective user IDs"); } boolean result = true; if ((mode & X_OK.value) != 0) { - result = result && isExecutable(file); + result = isExecutable(file); } if ((mode & R_OK.value) != 0) { result = result && isReadable(file); @@ -2092,14 +1875,10 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, return result; } - @ExportMessage - public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + @Override + @TruffleBoundary + public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); Set permissions = modeToPosixFilePermissions(mode); if (getPythonOS() == PLATFORM_WIN32) { // cmp cpython's simple chmod implementation @@ -2111,46 +1890,43 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, try { file.setPosixPermissions(permissions, getLinkOptions(followSymlinks)); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } } - @ExportMessage - public void fchmod(int fd, int mode, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { - TruffleString path = getFilePath(fd, fromJavaStringNode); + @Override + @TruffleBoundary + public void fchmod(int fd, int mode) throws PosixException { + String path = getFilePath(fd); if (path == null) { throw posixException(OSErrorEnum.EBADF); } - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(path); Set permissions = modeToPosixFilePermissions(mode); try { file.setPosixPermissions(permissions); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage + @Override + @TruffleBoundary public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { throw createUnsupportedFeature("fchownat"); } - @ExportMessage + @Override + @TruffleBoundary public void fchown(int fd, long owner, long group) throws PosixException { throw createUnsupportedFeature("fchown"); } - @ExportMessage - public Object readlinkat(int dirFd, Object path, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile defaultDirFdPofile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) throws PosixException { - TruffleFile file = resolvePath(inliningTarget, dirFd, pathToTruffleString(path, fromJavaStringNode), defaultDirFdPofile, eqNode, toJavaStringNode); + @Override + @TruffleBoundary + public Object readlinkat(int dirFd, Object path) throws PosixException { + TruffleFile file = resolvePath(dirFd, pathToJavaString(path)); try { TruffleFile canonicalFile = file.getCanonicalFile(); if (file.equals(canonicalFile)) { @@ -2160,14 +1936,14 @@ public Object readlinkat(int dirFd, Object path, } catch (PosixException e) { throw e; } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - public void kill(long pid, int signal, - @Bind Node inliningTarget) throws PosixException { - PythonContext context = PythonContext.get(inliningTarget); + @Override + @TruffleBoundary + public void kill(long pid, int signal) throws PosixException { + PythonContext context = this.context; try { if (signal == signalFromName(context, "KILL")) { sigkill((int) pid); @@ -2183,13 +1959,14 @@ public void kill(long pid, int signal, } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void raise(int signal) throws PosixException { throw createUnsupportedFeature("raise"); } - @ExportMessage + @Override @TruffleBoundary public synchronized int alarm(int seconds) { int remaining = 0; @@ -2209,7 +1986,7 @@ public synchronized int alarm(int seconds) { return remaining; } - @ExportMessage + @Override @TruffleBoundary public synchronized Timeval[] getitimer(int which) throws PosixException { if (which != 0) { @@ -2218,7 +1995,7 @@ public synchronized Timeval[] getitimer(int which) throws PosixException { return currentItimer(); } - @ExportMessage + @Override @TruffleBoundary public synchronized Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { if (which != 0 || delay.getSeconds() < 0 || delay.getMicroseconds() < 0 || interval.getSeconds() < 0 || interval.getMicroseconds() < 0) { @@ -2315,25 +2092,27 @@ int getRemainingSeconds() { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void signalSelf(int signal) throws PosixException { throw createUnsupportedFeature("signalSelf"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public long killpg(long pgid, int signal) throws PosixException { + public void killpg(long pgid, int signal) throws PosixException { throw createUnsupportedFeature("killpg"); } - @ExportMessage - public long[] waitpid(long pid, int options, - @CachedLibrary("this") PosixSupportLibrary posixLib) throws PosixException { + @Override + @TruffleBoundary + public long[] waitpid(Node location, long pid, int options) throws PosixException { try { if (options == 0) { int[] exitStatus = new int[1]; - TruffleSafepoint.setBlockedThreadInterruptible(posixLib, (s) -> { + TruffleSafepoint.setBlockedThreadInterruptible(location, (s) -> { exitStatus[0] = s.waitpid((int) pid); }, this); return new long[]{pid, exitStatus[0]}; @@ -2355,63 +2134,66 @@ public long[] waitpid(long pid, int options, } } - @TruffleBoundary - private static void interruptThread() { - Thread.currentThread().interrupt(); - } - // TODO the implementation of the following builtins is taken from posix.py, - // do they really make sense for the emulated backend? Is the handling of exist status correct? + // do they really make sense for the emulated backend? Is the handling of exit status correct? - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wcoredump(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifcontinued(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifstopped(int status) { return false; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifsignaled(int status) { return status > 128; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public boolean wifexited(int status) { return !wifsignaled(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wexitstatus(int status) { return status & 127; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wtermsig(int status) { return status - 128; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) @SuppressWarnings("static-method") public int wstopsig(int status) { return 0; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getuid() { @@ -2427,14 +2209,14 @@ public long getuid() { return 1000; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long geteuid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("geteuid"); } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getgid() { @@ -2450,50 +2232,56 @@ public long getgid() { return 1000; } - @ExportMessage + @Override @SuppressWarnings("static-method") @TruffleBoundary public long getegid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getegid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getppid() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getppid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getpgid(long pid) throws PosixException { throw createUnsupportedFeature("getpgid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void setpgid(long pid, long pgid) throws PosixException { throw createUnsupportedFeature("setpgid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getpgrp() throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("getpgrp"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long getsid(long pid) throws PosixException { throw createUnsupportedFeature("getsid"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long setsid() throws PosixException { throw createUnsupportedFeature("getsid"); } - @ExportMessage + @Override @TruffleBoundary public long[] getgroups() throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { @@ -2507,7 +2295,7 @@ public long[] getgroups() throws PosixException { throw new UnsupportedPosixFeatureException("getgroups was excluded"); } - @ExportMessage + @Override @TruffleBoundary public RusageResult getrusage(int who) throws PosixException { Runtime runtime = Runtime.getRuntime(); @@ -2526,8 +2314,7 @@ public RusageResult getrusage(int who) throws PosixException { ru_stime = Math.max(0, (threadMXBean.getThreadCpuTime(id) - threadMXBean.getThreadUserTime(id))) / 1000000000.0; } - if (threadMXBean instanceof com.sun.management.ThreadMXBean) { - com.sun.management.ThreadMXBean thMxBean = (com.sun.management.ThreadMXBean) threadMXBean; + if (threadMXBean instanceof com.sun.management.ThreadMXBean thMxBean) { ru_maxrss = thMxBean.getThreadAllocatedBytes(id); } else { ru_maxrss = runtime.maxMemory(); @@ -2571,19 +2358,21 @@ public RusageResult getrusage(int who) throws PosixException { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public OpenPtyResult openpty() throws PosixException { throw createUnsupportedFeature("openpty"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public TruffleString ctermid() { + public String ctermid() { return T_DEV_TTY; } - @ExportMessage + @Override @TruffleBoundary public void setenv(Object name, Object value, boolean overwrite) { String nameStr = pathToJavaString(name); @@ -2595,18 +2384,17 @@ public void setenv(Object name, Object value, boolean overwrite) { } } - @ExportMessage + @Override @TruffleBoundary public void unsetenv(Object name) { String nameStr = pathToJavaString(name); environ.remove(nameStr); } - @ExportMessage + @Override @TruffleBoundary public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { if (PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { throw new UnsupportedPosixFeatureException("forkExec was excluded"); } @@ -2618,7 +2406,7 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en // compatibility warning // TODO do we need to do this check (and the isExecutable() check later)? - TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToTruffleString(cwd, fromJavaStringNode), TruffleString.EqualNode.getUncached()); + TruffleFile cwdFile = cwd == null ? context.getEnv().getCurrentWorkingDirectory() : getTruffleFile(pathToJavaString(cwd)); if (!cwdFile.exists()) { throw posixException(OSErrorEnum.ENOENT); } @@ -2759,7 +2547,7 @@ private void handleIOError(int errpipe_write, IOException e) { if (e == null) { pair = new ErrorAndMessagePair(OSErrorEnum.ENOENT, OSErrorEnum.ENOENT.getMessage()); } else { - pair = OSErrorEnum.fromException(e, TruffleString.EqualNode.getUncached()); + pair = OSErrorEnum.fromException(e); } try { errChannel.write(ByteBuffer.wrap(("OSError:" + Long.toHexString(pair.oserror.getNumber()) + ":" + pair.message).getBytes())); @@ -2769,9 +2557,9 @@ private void handleIOError(int errpipe_write, IOException e) { } } - @ExportMessage - public void execv(Object pathname, Object[] args, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public void execv(Object pathname, Object[] args) throws PosixException { assert args.length > 0; String[] cmd = new String[args.length]; // ProcessBuilder does not accept separate executable name, we must overwrite the 0-th @@ -2783,7 +2571,7 @@ public void execv(Object pathname, Object[] args, try { execvInternal(cmd); } catch (Exception e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } throw shouldNotReachHere("Execv must not return normally"); } @@ -2819,7 +2607,7 @@ private void execvInternal(String[] cmd) throws IOException { throw new PythonExitException(null, pr.exitValue()); } - @ExportMessage + @Override @TruffleBoundary public int system(Object commandObj) { if (PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { @@ -2940,31 +2728,31 @@ public boolean isOpen() { } @Override - public void close() throws IOException { + public void close() { open = false; } @Override - public int read(ByteBuffer dst) throws IOException { + public int read(ByteBuffer dst) { int nread = Math.min(dst.remaining(), data.length - cur); dst.put(data, cur, nread); return nread; } @Override - public int write(ByteBuffer src) throws IOException { + public int write(ByteBuffer src) { int nwrite = Math.min(src.remaining(), data.length - cur); src.get(data, cur, nwrite); return nwrite; } @Override - public long position() throws IOException { + public long position() { return cur; } @Override - public SeekableByteChannel position(long newPosition) throws IOException { + public SeekableByteChannel position(long newPosition) { if (newPosition < 0 || newPosition >= data.length) { throw new IllegalArgumentException(); } @@ -2973,12 +2761,12 @@ public SeekableByteChannel position(long newPosition) throws IOException { } @Override - public long size() throws IOException { + public long size() { return data.length; } @Override - public SeekableByteChannel truncate(long size) throws IOException { + public SeekableByteChannel truncate(long size) { for (int i = 0; i < size; i++) { data[i] = 0; } @@ -2986,19 +2774,15 @@ public SeekableByteChannel truncate(long size) throws IOException { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname, - @Bind Node inliningTarget, - @Shared("defaultDirProfile") @Cached InlinedConditionProfile isAnonymousProfile, - @Shared("eq") @Cached TruffleString.EqualNode eqNode, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) throws PosixException { + public MMapHandle mmap(@SuppressWarnings("unused") Node location, long length, int prot, int flags, int fd, long offset, @SuppressWarnings("unused") Object tagname) throws PosixException { if (prot == PROT_NONE.value) { return MMapHandle.NONE; } - // Note: the profile is not really defaultDirProfile, but it's good to share... - if (isAnonymousProfile.profile(inliningTarget, (flags & MAP_ANONYMOUS.value) != 0)) { + if ((flags & MAP_ANONYMOUS.value) != 0) { try { return new MMapHandle(new AnonymousMap(PythonUtils.toIntExact(length)), 0); } catch (OverflowException e) { @@ -3006,18 +2790,17 @@ final MMapHandle mmap(long length, int prot, int flags, int fd, long offset, @Su } } - TruffleString path = getFilePath(fd, fromJavaStringNode); - TruffleFile file = getTruffleFile(path, eqNode); + TruffleFile file = getTruffleFile(getFilePath(fd)); Set options = mmapProtToOptions(prot); // we create a new channel, the file may be closed but the mmap object should still work SeekableByteChannel fileChannel; try { - fileChannel = newByteChannel(file, options); - position(fileChannel, offset); + fileChannel = file.newByteChannel(options); + fileChannel.position(offset); return new MMapHandle(fileChannel, offset); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } @@ -3036,107 +2819,76 @@ private static Set mmapProtToOptions(int prot) throws PosixE return options; } + @Override @TruffleBoundary - private static SeekableByteChannel newByteChannel(TruffleFile file, Set options) throws IOException { - return file.newByteChannel(options); - } - - @ExportMessage - @SuppressWarnings("static-method") - public byte mmapReadByte(Object mmap, long index, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + public byte mmapReadByte(Object mmap, long index) throws PosixException { if (mmap == MMapHandle.NONE) { - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; - ByteBuffer readingBuffer = allocateByteBuffer(1); - int readSize = readBytes(inliningTarget, handle, index, readingBuffer, errBranch, eqNode); + ByteBuffer readingBuffer = ByteBuffer.allocate(1); + int readSize = readBytes(handle, index, readingBuffer); if (readSize == 0) { throw posixException(OSErrorEnum.ENODATA); } - return getByte(readingBuffer); + readingBuffer.flip(); + return readingBuffer.get(); } - @ExportMessage - @SuppressWarnings("static-method") - public void mmapWriteByte(Object mmap, long index, byte value, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { - mmapWriteBytes(mmap, index, new byte[]{value}, 1, inliningTarget, errBranch, eqNode); + @Override + @TruffleBoundary + public void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { + mmapWriteBytes(mmap, index, new byte[]{value}, 1); } - @ExportMessage - @SuppressWarnings("static-method") - public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { if (mmap == MMapHandle.NONE) { - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; - int sz; - try { - sz = PythonUtils.toIntExact(length); - } catch (OverflowException e) { - errBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.EOVERFLOW); - } - ByteBuffer readingBuffer = allocateByteBuffer(sz); - int readSize = readBytes(inliningTarget, handle, index, readingBuffer, errBranch, eqNode); + ByteBuffer readingBuffer = ByteBuffer.allocate(length); + int readSize = readBytes(handle, index, readingBuffer); if (readSize > 0) { - getByteBufferArray(readingBuffer, bytes, readSize); + readingBuffer.flip(); + readingBuffer.get(bytes, 0, readSize); } return readSize; } - private static int readBytes(Node inliningTarget, MMapHandle handle, long index, ByteBuffer readingBuffer, InlinedBranchProfile errBranch, TruffleString.EqualNode eqNode) throws PosixException { + private static int readBytes(MMapHandle handle, long index, ByteBuffer readingBuffer) throws PosixException { try { - position(handle.channel, index + handle.offset); - return readChannel(handle.channel, readingBuffer); + handle.channel.position(index + handle.offset); + return handle.channel.read(readingBuffer); } catch (IOException e) { - errBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } - @ExportMessage - @SuppressWarnings("static-method") - public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @Bind Node inliningTarget, - @Shared("errorBranch") @Cached InlinedBranchProfile errBranch, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { if (mmap == MMapHandle.NONE) { - errBranch.enter(inliningTarget); throw posixException(OSErrorEnum.EACCES); } MMapHandle handle = (MMapHandle) mmap; try { SeekableByteChannel channel = handle.channel; - position(channel, handle.offset + index); - int written = writeChannel(channel, bytes, length); + channel.position(handle.offset + index); + int written = channel.write(ByteBuffer.wrap(bytes, 0, length)); if (written != length) { throw posixException(OSErrorEnum.EIO); } } catch (Exception e) { // Catching generic Exception to also cover NonWritableChannelException - errBranch.enter(inliningTarget); - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } } + @Override @TruffleBoundary - private static int writeChannel(SeekableByteChannel channel, byte[] bytes, int length) throws IOException { - return channel.write(ByteBuffer.wrap(bytes, 0, length)); - } - - @ExportMessage - @SuppressWarnings({"static-method", "unused"}) + @SuppressWarnings("unused") public void mmapFlush(Object mmap, long offset, long length) { // Intentionally noop // If we had access to the underlying NIO FileChannel, we could explicitly set force(true) @@ -3145,126 +2897,102 @@ public void mmapFlush(Object mmap, long offset, long length) { // different implementation of mmap in emulated posix) } - @ExportMessage - @SuppressWarnings("static-method") - public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public void mmapUnmap(Object mmap, @SuppressWarnings("unused") long length) throws PosixException { if (mmap == MMapHandle.NONE) { return; } MMapHandle handle = (MMapHandle) mmap; if (handle.channel != null) { try { - closeChannel(handle.channel); + handle.channel.close(); } catch (IOException e) { - throw posixException(OSErrorEnum.fromException(e, eqNode)); + throw posixException(OSErrorEnum.fromException(e)); } handle.channel = null; } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public long mmapGetPointer(@SuppressWarnings("unused") Object mmap) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("obtaining mmap pointer"); } + @Override @TruffleBoundary - private static void closeChannel(Channel ch) throws IOException { - ch.close(); - } - - @TruffleBoundary - private static void position(SeekableByteChannel ch, long offset) throws IOException { - ch.position(offset); - } - - @TruffleBoundary(allowInlining = true) - private static ByteBuffer allocateByteBuffer(int n) { - return ByteBuffer.allocate(n); - } - - @TruffleBoundary(allowInlining = true) - protected static void getByteBufferArray(ByteBuffer src, byte[] dst, int readSize) { - src.flip(); - src.get(dst, 0, readSize); - } - - @TruffleBoundary(allowInlining = true) - protected static byte getByte(ByteBuffer src) { - src.flip(); - return src.get(); - } - - @TruffleBoundary - private static int readChannel(Object readableChannel, ByteBuffer dst) throws IOException { - return ((ReadableByteChannel) readableChannel).read(dst); - } - - @ExportMessage @SuppressWarnings("unused") - long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { + public long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semClose(long handle) throws PosixException { + public void semClose(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semUnlink(Object name) throws PosixException { + public void semUnlink(Object name) throws PosixException { throw posixException(OSErrorEnum.ENOENT); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - int shmOpen(Object name, int openFlags, int mode) throws PosixException { + public int shmOpen(Object name, int openFlags, int mode) throws PosixException { throw createUnsupportedFeature("shm_open"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void shmUnlink(Object name) throws PosixException { + public void shmUnlink(Object name) throws PosixException { throw createUnsupportedFeature("shm_unlink"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - int semGetValue(long handle) throws PosixException { + public int semGetValue(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semPost(long handle) throws PosixException { + public void semPost(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - void semWait(long handle) throws PosixException { + public void semWait(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - boolean semTryWait(long handle) throws PosixException { + public boolean semTryWait(long handle) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") - boolean semTimedWait(long handle, long deadlineNs) throws PosixException { + public boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { throw posixException(OSErrorEnum.EINVAL); } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") - public PwdResult getpwuid(long uid) throws PosixException { + public EmulatedPwdResult getpwuid(long uid) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { case PLATFORM_LINUX: @@ -3282,10 +3010,9 @@ public PwdResult getpwuid(long uid) throws PosixException { throw new UnsupportedPosixFeatureException("getpwuid was excluded"); } - @ExportMessage + @Override @TruffleBoundary - @SuppressWarnings("static-method") - public PwdResult getpwnam(Object name) throws PosixException { + public EmulatedPwdResult getpwnam(Object name) throws PosixException { if (!PythonImageBuildOptions.WITHOUT_PLATFORM_ACCESS) { switch (PythonLanguage.getPythonOS()) { case PLATFORM_LINUX: @@ -3303,38 +3030,39 @@ public PwdResult getpwnam(Object name) throws PosixException { throw new UnsupportedPosixFeatureException("getpwnam was excluded"); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary(allowInlining = true) public boolean hasGetpwentries() { return false; } - @ExportMessage - @SuppressWarnings("static-method") - public PwdResult[] getpwentries() throws PosixException { + @Override + @TruffleBoundary + public EmulatedPwdResult[] getpwentries() throws PosixException { throw createUnsupportedFeature("getpwent"); } - private static PwdResult createPwdResult(UnixSystem unix) { - TruffleString homeDir = toTruffleStringUncached(System.getProperty("user.home")); - return new PwdResult(toTruffleStringUncached(unix.getUsername()), unix.getUid(), unix.getGid(), homeDir, T_BIN_SH); + private static EmulatedPwdResult createPwdResult(UnixSystem unix) { + return new EmulatedPwdResult(unix.getUsername(), unix.getUid(), unix.getGid(), System.getProperty("user.home"), "/bin/sh"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { throw createUnsupportedFeature("ioctl"); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("unused") public int ioctlInt(int fd, long request, int arg) throws PosixException { throw createUnsupportedFeature("ioctl"); } - @ExportMessage - public int socket(int domain, int type, int protocol, - @Shared("eq") @Cached TruffleString.EqualNode eqNode) throws PosixException { + @Override + @TruffleBoundary + public int socket(int domain, int type, int protocol) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { throw new UnsupportedPosixFeatureException("socket was excluded"); } @@ -3353,11 +3081,11 @@ public int socket(int domain, int type, int protocol, } return assignFileDescriptor(socket); } catch (Exception e) { - throw posixException(e, eqNode); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public AcceptResult accept(int sockfd) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3372,7 +3100,7 @@ public AcceptResult accept(int sockfd) throws PosixException { c = null; return new AcceptResult(fd, addr); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } finally { if (c != null) { try { @@ -3384,7 +3112,7 @@ public AcceptResult accept(int sockfd) throws PosixException { } } - @ExportMessage + @Override @TruffleBoundary public void bind(int sockfd, UniversalSockAddr addr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3398,11 +3126,11 @@ public void bind(int sockfd, UniversalSockAddr addr) throws PosixException { try { socket.bind(usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public void connect(int sockfd, UniversalSockAddr addr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3416,11 +3144,11 @@ public void connect(int sockfd, UniversalSockAddr addr) throws PosixException { try { socket.connect(usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public void listen(int sockfd, int backlog) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3430,11 +3158,11 @@ public void listen(int sockfd, int backlog) throws PosixException { try { socket.listen(backlog); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public UniversalSockAddr getpeername(int sockfd) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3448,11 +3176,11 @@ public UniversalSockAddr getpeername(int sockfd) throws PosixException { } return EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public UniversalSockAddr getsockname(int sockfd) throws PosixException { EmulatedSocket socket = getEmulatedSocket(sockfd); @@ -3467,11 +3195,11 @@ public UniversalSockAddr getsockname(int sockfd) throws PosixException { } return EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3482,11 +3210,11 @@ public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws P try { return socket.send(bb, flags); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3501,11 +3229,11 @@ public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, Univer try { return socket.sendto(bb, flags, usa.socketAddress); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3516,11 +3244,11 @@ public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws P try { return socket.recv(bb, flags); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3532,22 +3260,22 @@ public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int SocketAddress sa = socket.recvfrom(bb, flags); return new RecvfromResult(bb.position(), EmulatedUniversalSockAddrImpl.fromSocketAddress(socket.family, sa)); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public void shutdown(int sockfd, int how) throws PosixException { EmulatedSocket socket = getEmulatedSocket(sockfd); try { socket.shutdown(how); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } - @ExportMessage + @Override @TruffleBoundary public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3590,7 +3318,7 @@ public int getsockopt(int sockfd, int level, int optname, byte[] optval, int opt } catch (UnsupportedOperationException e) { throw posixException(OSErrorEnum.ENOPROTOOPT); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3598,7 +3326,7 @@ private static ByteArraySupport nativeByteArraySupport() { return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? ByteArraySupport.littleEndian() : ByteArraySupport.bigEndian(); } - @ExportMessage + @Override @TruffleBoundary public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3632,7 +3360,7 @@ public void setsockopt(int sockfd, int level, int optname, byte[] optval, int op } catch (UnsupportedOperationException e) { throw posixException(OSErrorEnum.ENOPROTOOPT); } catch (Exception e) { - throw posixException(e, TruffleString.EqualNode.getUncached()); + throw posixException(e); } } @@ -3663,8 +3391,8 @@ private static boolean decodeBooleanOptVal(byte[] optval, int optlen) throws Pos return decodeIntOptVal(optval, optlen) != 0; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public int inet_addr(Object src) { try { return inet_aton(src); @@ -3673,8 +3401,7 @@ public int inet_addr(Object src) { } } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public int inet_aton(Object src) throws InvalidAddressException { String s = (String) src; @@ -3682,29 +3409,24 @@ public int inet_aton(Object src) throws InvalidAddressException { throw new InvalidAddressException(); } String[] parts = s.split("\\."); - switch (parts.length) { - case 1: - return parseUnsigned(parts[0], 0xFFFFFFFFL); - case 2: - return (parseUnsigned(parts[0], 0xFF) << 24) | parseUnsigned(parts[1], 0xFFFFFF); - case 3: - return (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | parseUnsigned(parts[2], 0xFFFF); - case 4: - return (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | (parseUnsigned(parts[2], 0xFF) << 8) | parseUnsigned(parts[3], 0xFF); - default: - throw new InvalidAddressException(); - } + return switch (parts.length) { + case 1 -> parseUnsigned(parts[0], 0xFFFFFFFFL); + case 2 -> (parseUnsigned(parts[0], 0xFF) << 24) | parseUnsigned(parts[1], 0xFFFFFF); + case 3 -> + (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | parseUnsigned(parts[2], 0xFFFF); + case 4 -> + (parseUnsigned(parts[0], 0xFF) << 24) | (parseUnsigned(parts[1], 0xFF) << 16) | (parseUnsigned(parts[2], 0xFF) << 8) | parseUnsigned(parts[3], 0xFF); + default -> throw new InvalidAddressException(); + }; } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public Object inet_ntoa(int address) { return String.format("%d.%d.%d.%d", (address >> 24) & 0xFF, (address >> 16) & 0xFF, (address >> 8) & 0xFF, address & 0xFF); } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { byte[] bytes; @@ -3736,8 +3458,7 @@ public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAd throw posixException(OSErrorEnum.EAFNOSUPPORT); } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public Object inet_ntop(int family, byte[] src) throws PosixException { if (family != AF_INET.value && family != AF_INET6.value) { @@ -3759,14 +3480,13 @@ public Object inet_ntop(int family, byte[] src) throws PosixException { } } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object gethostname() throws PosixException { return getHostName(withoutIOSocket); } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3800,7 +3520,6 @@ public Object[] getnameinfo(UniversalSockAddr addr, int flags) throws Unsupporte return new Object[]{host, service}; } - @TruffleBoundary private String searchServicesForPort(TruffleLanguage.Env env, int port, String protocol) { Map> services = getServices(); Set servicesNames = services.keySet(); @@ -3816,8 +3535,7 @@ private String searchServicesForPort(TruffleLanguage.Env env, int port, String p return null; } - @ExportMessage - @SuppressWarnings("static-method") + @Override @TruffleBoundary public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { if (PythonImageBuildOptions.WITHOUT_JAVA_INET || withoutIOSocket) { @@ -3918,7 +3636,6 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s return new EmulatedAddrInfoCursorImpl(items.iterator(), canonName, protocol, flags); } - @ExportLibrary(AddrInfoCursorLibrary.class) protected static class EmulatedAddrInfoCursorImpl implements AddrInfoCursor { final Iterator iterator; final String canonName; @@ -3934,15 +3651,16 @@ protected static class EmulatedAddrInfoCursorImpl implements AddrInfoCursor { item = iterator.next(); } - @ExportMessage - final void release() { + @Override + @TruffleBoundary + public final void release() { checkReleased(); item = null; } - @ExportMessage + @Override @TruffleBoundary - final boolean next() { + public final boolean next() { if (!iterator.hasNext()) { return false; } @@ -3950,36 +3668,42 @@ final boolean next() { return true; } - @ExportMessage - final int getFlags() { + @Override + @TruffleBoundary + public final int getFlags() { return flags; } - @ExportMessage - final int getFamily() { + @Override + @TruffleBoundary + public final int getFamily() { return item.address.getFamily(); } - @ExportMessage - final int getSockType() { + @Override + @TruffleBoundary + public final int getSockType() { return item.socketType; } - @ExportMessage - final int getProtocol() { + @Override + @TruffleBoundary + public final int getProtocol() { if (protocol != 0) { return protocol; } return item.socketType == SOCK_DGRAM.value ? IPPROTO_UDP.value : IPPROTO_TCP.value; } - @ExportMessage - final Object getCanonName() { + @Override + @TruffleBoundary + public final Object getCanonName() { return canonName; } - @ExportMessage - final UniversalSockAddr getSockAddr() { + @Override + @TruffleBoundary + public final UniversalSockAddr getSockAddr() { return item.address; } @@ -4000,22 +3724,24 @@ static final class Item { } } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { return EmulatedUniversalSockAddrImpl.inet4(src.getAddressAsBytes(), src.getPort()); } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { return EmulatedUniversalSockAddrImpl.inet6(src.getAddress(), src.getScopeId(), src.getPort()); } - @ExportMessage - UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException { throw createUnsupportedFeature("AF_UNIX"); } - @ExportLibrary(UniversalSockAddrLibrary.class) protected static class EmulatedUniversalSockAddrImpl implements UniversalSockAddr { final int family; final InetSocketAddress socketAddress; @@ -4026,29 +3752,29 @@ private EmulatedUniversalSockAddrImpl(int family, InetSocketAddress socketAddres this.socketAddress = socketAddress; } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { return family; } - @ExportMessage + @Override @TruffleBoundary - Inet4SockAddr asInet4SockAddr() { + public Inet4SockAddr asInet4SockAddr() { if (getFamily() != AF_INET.value) { throw new IllegalArgumentException("Only AF_INET socket address can be converted to Inet4SockAddr"); } return new Inet4SockAddr(socketAddress.getPort(), socketAddress.getAddress().getAddress()); } - @ExportMessage + @Override @TruffleBoundary - Inet6SockAddr asInet6SockAddr() { + public Inet6SockAddr asInet6SockAddr() { if (getFamily() != AF_INET6.value) { throw new IllegalArgumentException("Only AF_INET6 socket address can be converted to Inet6SockAddr"); } InetAddress sa = socketAddress.getAddress(); - if (sa instanceof Inet6Address) { - Inet6Address a = (Inet6Address) sa; + if (sa instanceof Inet6Address a) { return new Inet6SockAddr(socketAddress.getPort(), a.getAddress(), 0, a.getScopeId()); } // IPv4 mapped to IPv6 @@ -4057,9 +3783,9 @@ Inet6SockAddr asInet6SockAddr() { return new Inet6SockAddr(socketAddress.getPort(), ipv6, 0, 0); } - @ExportMessage + @Override @TruffleBoundary - UnixSockAddr asUnixSockAddr() { + public UnixSockAddr asUnixSockAddr() { assert getFamily() != AF_UNIX.value; throw new IllegalArgumentException("Only AF_UNIX socket address can be converted to Unix4SockAddr"); } @@ -4189,7 +3915,7 @@ public int write(ByteBuffer src) throws IOException { } @Override - EmulatedSocket accept() throws IOException { + EmulatedSocket accept() { throw new UnsupportedOperationException(); } @@ -4206,7 +3932,7 @@ void connect(SocketAddress socketAddress) throws IOException { } @Override - void listen(int backlog) throws IOException { + void listen(int backlog) { throw new UnsupportedOperationException(); } @@ -4262,7 +3988,7 @@ int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) throws IOException } @Override - void shutdown(int how) throws IOException { + void shutdown(int how) { // TODO what does native SOCK_DGRAM shutdown do? } @@ -4403,7 +4129,7 @@ EmulatedStreamSocket accept() throws IOException { } @Override - synchronized void bind(SocketAddress socketAddress) throws IOException { + synchronized void bind(SocketAddress socketAddress) { neverPartOfCompilation(); if (clientChannel != null || serverChannel != null || bindAddress != null) { // already bound @@ -4522,7 +4248,7 @@ int send(ByteBuffer bb, int flags) throws IOException { } @Override - int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) throws IOException { + int sendto(ByteBuffer bb, int flags, SocketAddress destAddr) { neverPartOfCompilation(); // sendto() makes sense only for DGRAM sockets throw new AlreadyConnectedException(); @@ -4647,75 +4373,35 @@ private static byte[] mapIPv4toIPv6(byte[] ipv4) { } // ------------------ - // Path conversions - - @ExportMessage - @SuppressWarnings("static-method") - public Object createPathFromString(TruffleString path, - @Bind Node inliningTarget, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode, - @Exclusive @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { - String javaPath = getPythonOS() == PLATFORM_WIN32 - ? toJavaStringNode.execute(path) - : createUTF8String(encodeFSDefaultNode.execute(null, inliningTarget, path)); - return checkEmbeddedNulls(javaPath); - } - - @ExportMessage - @SuppressWarnings("static-method") - public Object createPathFromBytes(byte[] path) { - return checkEmbeddedNulls(createUTF8String(path)); - } + // Raw Java representations used by PosixSupportNodes. - @ExportMessage - @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) path, TS_ENCODING); + @TruffleBoundary + public Object createRawPath(String path) { + return checkEmbeddedNulls(path); } - @ExportMessage - @SuppressWarnings("static-method") - public Buffer getPathAsBytes(Object path) { - return Buffer.wrap(utf8StringToBytes((String) path)); + public String getRawPath(Object path) { + return (String) path; } - @ExportMessage - public Object createCStringFromString(TruffleString string, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) { - return checkEmbeddedNulls(toJavaStringNode.execute(string)); + @TruffleBoundary + public Object createRawCString(String string) { + return checkEmbeddedNulls(string); } - @ExportMessage + @Override + @TruffleBoundary public Object createCStringFromBytes(byte[] bytes) { - return checkEmbeddedNulls(createUTF8String(bytes)); - } - - @ExportMessage - public Object createWideStringFromString(TruffleString string, - @Shared("ts2js") @Cached TruffleString.ToJavaStringNode toJavaStringNode) { - return checkEmbeddedNulls(toJavaStringNode.execute(string)); - } - - @ExportMessage - public TruffleString getCStringAsString(Object string, - @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) string, TS_ENCODING); - } - - @ExportMessage - public Buffer getCStringAsBytes(Object string) { - return Buffer.wrap(utf8StringToBytes((String) string)); + return checkEmbeddedNulls(new String(bytes, StandardCharsets.UTF_8)); } @TruffleBoundary - private static String createUTF8String(byte[] retbuf) { - return new String(retbuf, StandardCharsets.UTF_8); + public Object createRawWideString(String string) { + return checkEmbeddedNulls(string); } - @TruffleBoundary - private static byte[] utf8StringToBytes(String str) { - return str.getBytes(StandardCharsets.UTF_8); + public String getRawCString(Object string) { + return (String) string; } private static String checkEmbeddedNulls(String s) { @@ -4817,11 +4503,11 @@ static PosixException posixException(OSErrorEnum osError) throws PosixException throw new PosixErrnoException(osError.getNumber(), osError.getMessage()); } - private static PosixException posixException(Exception e, TruffleString.EqualNode eqNode) throws PosixException { + private static PosixException posixException(Exception e) throws PosixException { if (e instanceof PosixException) { throw (PosixException) e; } - ErrorAndMessagePair pair = OSErrorEnum.fromException(e, eqNode); + ErrorAndMessagePair pair = OSErrorEnum.fromException(e); throw new PosixErrnoException(pair.oserror.getNumber(), pair.message); } @@ -4829,23 +4515,17 @@ private static PosixException posixException(ErrorAndMessagePair pair) throws Po throw new PosixErrnoException(pair.oserror.getNumber(), pair.message); } - @TruffleBoundary - static long fileTimeToSeconds(FileTime t) { - return t.to(TimeUnit.SECONDS); - } - - @TruffleBoundary - static long fileTimeNanoSecondsPart(FileTime t) { + private static long fileTimeNanoSecondsPart(FileTime t) { return t.toInstant().getNano(); } - private TruffleFile getTruffleFile(TruffleString path, TruffleString.EqualNode eqNode) throws PosixException { + private TruffleFile getTruffleFile(String path) throws PosixException { try { return context.getPublicTruffleFileRelaxed(path, PythonLanguage.T_DEFAULT_PYTHON_EXTENSIONS); } catch (Exception ex) { // So far it seem that this can only be InvalidPath exception from Java NIO, but we stay // on the safe side and catch generic exception - throw posixException(OSErrorEnum.fromException(ex, eqNode)); + throw posixException(OSErrorEnum.fromException(ex)); } } @@ -4853,48 +4533,29 @@ private TruffleFile getTruffleFile(TruffleString path, TruffleString.EqualNode e * Resolves the path relative to the directory given as file descriptor. Honors the * {@link PosixConstants#AT_FDCWD}. */ - private TruffleFile resolvePath(Node inliningTarget, int dirFd, TruffleString pathname, InlinedConditionProfile defaultDirFdPofile, TruffleString.EqualNode eqNode, - TruffleString.ToJavaStringNode toJavaStringNode) - throws PosixException { - if (defaultDirFdPofile.profile(inliningTarget, dirFd == AT_FDCWD.value)) { - return getTruffleFile(pathname, eqNode); - } else { - TruffleFile file = getTruffleFile(pathname, eqNode); - if (file.isAbsolute()) { - // Even if the dirFd is non-existing or otherwise wrong, we should not trigger - // any error if the file path is already absolute - return file; - } - TruffleString dirPath = getFilePathOrDefault(dirFd, null); - if (dirPath == null) { - throw posixException(OSErrorEnum.EBADF); - } - TruffleFile dir = getTruffleFile(dirPath, eqNode); - return dir.resolve(toJavaStringNode.execute(pathname)); + private TruffleFile resolvePath(int dirFd, String pathname) throws PosixException { + if (dirFd == AT_FDCWD.value) { + return getTruffleFile(pathname); } - } - private static TruffleString pathToTruffleString(Object path, TruffleString.FromJavaStringNode fromJavaStringNode) { - return fromJavaStringNode.execute((String) path, TS_ENCODING); + TruffleFile file = getTruffleFile(pathname); + if (file.isAbsolute()) { + // Even if the dirFd is non-existing or otherwise wrong, we should not trigger + // any error if the file path is already absolute + return file; + } + String dirPath = filePaths.get(dirFd); + if (dirPath == null) { + throw posixException(OSErrorEnum.EBADF); + } + TruffleFile dir = getTruffleFile(dirPath); + return dir.resolve(pathname); } private static String pathToJavaString(Object path) { return (String) path; } - @TruffleBoundary(allowInlining = true) - private TruffleString getFilePathOrDefault(int fd, String defaultValue) { - String path = filePaths.getOrDefault(fd, defaultValue); - return path != null ? toTruffleStringUncached(path) : null; - } - - @TruffleBoundary(allowInlining = true) - private static FileAttribute> modeToAttributes(int fileMode) { - Set perms = modeToPosixFilePermissions(fileMode); - return PosixFilePermissions.asFileAttribute(perms); - } - - @TruffleBoundary(allowInlining = true) private static Set modeToPosixFilePermissions(int fileMode) { HashSet perms = new HashSet<>(Arrays.asList(ownerBitsToPermission[fileMode >> 6 & 7])); perms.addAll(Arrays.asList(groupBitsToPermission[fileMode >> 3 & 7])); @@ -4902,7 +4563,6 @@ private static Set modeToPosixFilePermissions(int fileMode) return perms; } - @TruffleBoundary(allowInlining = true) private static Set flagsToOptions(int flags) { Set options = new HashSet<>(); int maskedFlags = flags & (O_RDONLY.value | O_WRONLY.value | O_RDWR.value); @@ -4953,7 +4613,7 @@ private static Set flagsToOptions(int flags) { } public static LinkOption[] getLinkOptions(boolean followSymlinks) { - return followSymlinks ? new LinkOption[0] : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; + return followSymlinks ? NO_LINK_OPTIONS : new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; } private static final TruffleLogger LOGGER = PythonLanguage.getLogger(EmulatedPosixSupport.class); @@ -4975,9 +4635,4 @@ public static void compatibilityIgnored(String fmt, Object... args) { private static String getIgnoredMessage(String fmt, Object[] args) { return "Ignored: " + String.format(fmt, args); } - - private TruffleString getFilePath(int fd, TruffleString.FromJavaStringNode fromJavaStringNode) { - String path = getFilePath(fd); - return path != null ? fromJavaStringNode.execute(path, TS_ENCODING) : null; - } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java index f6407c5abc..17f02f7a88 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java @@ -46,35 +46,13 @@ import java.util.logging.Level; import com.oracle.graal.python.PythonLanguage; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.frame.FrameInstance; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; @@ -98,7 +76,6 @@ *
  • FINEST - supporting messages (e.g. path conversions) + top 5 frames of the call stack
  • * */ -@ExportLibrary(PosixSupportLibrary.class) public class LoggingPosixSupport extends PosixSupport { private static final TruffleLogger LOGGER = PythonLanguage.getLogger(LoggingPosixSupport.class); @@ -107,10 +84,29 @@ public class LoggingPosixSupport extends PosixSupport { protected final PosixSupport delegate; public LoggingPosixSupport(PosixSupport delegate) { + CompilerAsserts.neverPartOfCompilation(); + if (delegate instanceof LoggingPosixSupport) { + throw new IllegalArgumentException(); + } this.delegate = delegate; LOGGER.log(Level.INFO, "Using " + delegate.getClass()); } + public PosixSupport getDelegate() { + assert !(delegate instanceof LoggingPosixSupport); + return delegate; + } + + @TruffleBoundary + public void logConversionEnter(String name, Object argument) { + logEnter(Level.FINEST, name, "%s", argument); + } + + @TruffleBoundary + public T logConversionExit(String name, T result) { + return logExit(Level.FINEST, name, "%s", result); + } + public static boolean isEnabled() { return LoggingPosixSupport.LOGGER.isLoggable(DEFAULT_LEVEL); } @@ -120,66 +116,66 @@ public void setEnv(Env env) { delegate.setEnv(env); } - @ExportMessage - final TruffleString getBackend( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final TruffleString getBackend() { logEnter(Level.FINEST, "getBackend", ""); - return logExit(Level.FINEST, "getBackend", "%s", lib.getBackend(delegate)); + return logExit(Level.FINEST, "getBackend", "%s", delegate.getBackend()); } - @ExportMessage - final TruffleString strerror(int errorCode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final TruffleString strerror(int errorCode) { logEnter(Level.FINEST, "strerror", "%d", errorCode); - return logExit(Level.FINEST, "strerror", "%s", lib.strerror(delegate, errorCode)); + return logExit(Level.FINEST, "strerror", "%s", delegate.strerror(errorCode)); } - @ExportMessage - final long getpid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final long getpid() { logEnter("getpid", ""); - return logExit("getpid", "%d", lib.getpid(delegate)); + return logExit("getpid", "%d", delegate.getpid()); } - @ExportMessage - final int umask(int mask, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int umask(int mask) throws PosixException { logEnter("umask", "0%o", mask); try { - return logExit("umask", "0%o", lib.umask(delegate, mask)); + return logExit("umask", "0%o", delegate.umask(mask)); } catch (PosixException e) { throw logException("umask", e); } } - @ExportMessage - final int openat(int dirFd, Object pathname, int flags, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { logEnter("openAt", "%d, %s, 0x%x, 0%o", dirFd, pathname, flags, mode); try { - return logExit("openAt", "%d", lib.openat(delegate, dirFd, pathname, flags, mode)); + return logExit("openAt", "%d", delegate.openat(dirFd, pathname, flags, mode)); } catch (PosixException e) { throw logException("openAt", e); } } - @ExportMessage - final int close(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int close(int fd) throws PosixException { logEnter("close", "%d", fd); try { - return lib.close(delegate, fd); + return delegate.close(fd); } catch (PosixException e) { throw logException("close", e); } } - @ExportMessage - final Buffer read(int fd, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Buffer read(int fd, long length) throws PosixException { logEnter("read", "%d, %d", fd, length); try { - Buffer retVal = lib.read(delegate, fd, length); + Buffer retVal = delegate.read(fd, length); logExit("read", "%d", retVal.length); return retVal; } catch (PosixException e) { @@ -187,1311 +183,1331 @@ final Buffer read(int fd, long length, } } - @ExportMessage - final long write(int fd, Buffer data, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long write(int fd, Buffer data) throws PosixException { logEnter("write", "%d, %d", fd, data.length); try { - return logExit("write", "%d", lib.write(delegate, fd, data)); + return logExit("write", "%d", delegate.write(fd, data)); } catch (PosixException e) { throw logException("write", e); } } - @ExportMessage - final int dup(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int getWindowsConsoleType(int fd) { + logEnter("getWindowsConsoleType", "%d", fd); + return logExit("getWindowsConsoleType", "%d", delegate.getWindowsConsoleType(fd)); + } + + @Override + @TruffleBoundary + public final long writeWindowsConsole(int fd, Buffer data) throws PosixException { + logEnter("writeWindowsConsole", "%d, %d", fd, data.length); + try { + return logExit("writeWindowsConsole", "%d", delegate.writeWindowsConsole(fd, data)); + } catch (PosixException e) { + throw logException("writeWindowsConsole", e); + } + } + + @Override + @TruffleBoundary + public final int dup(int fd) throws PosixException { logEnter("dup", "%d", fd); try { - return logExit("dup", "%d", lib.dup(delegate, fd)); + return logExit("dup", "%d", delegate.dup(fd)); } catch (PosixException e) { throw logException("dup", e); } } - @ExportMessage - final int dup2(int fd, int fd2, boolean inheritable, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { logEnter("dup2", "%d, %d, %b", fd, fd2, inheritable); try { - return logExit("dup2", "%d", lib.dup2(delegate, fd, fd2, inheritable)); + return logExit("dup2", "%d", delegate.dup2(fd, fd2, inheritable)); } catch (PosixException e) { throw logException("dup2", e); } } - @ExportMessage - final boolean getInheritable(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean getInheritable(int fd) throws PosixException { logEnter("getInheritable", "%d", fd); try { - return logExit("getInheritable", "%b", lib.getInheritable(delegate, fd)); + return logExit("getInheritable", "%b", delegate.getInheritable(fd)); } catch (PosixException e) { throw logException("getInheritable", e); } } - @ExportMessage - final void setInheritable(int fd, boolean inheritable, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setInheritable(int fd, boolean inheritable) throws PosixException { logEnter("setInheritable", "%d, %b", fd, inheritable); try { - lib.setInheritable(delegate, fd, inheritable); + delegate.setInheritable(fd, inheritable); } catch (PosixException e) { throw logException("setInheritable", e); } } - @ExportMessage - final long getOsfHandle(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long getOsfHandle(int fd) throws PosixException { logEnter("getOsfHandle", "%d", fd); try { - return logExit("getOsfHandle", "%d", lib.getOsfHandle(delegate, fd)); + return logExit("getOsfHandle", "%d", delegate.getOsfHandle(fd)); } catch (PosixException e) { throw logException("getOsfHandle", e); } } - @ExportMessage - final int openOsfHandle(long handle, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int openOsfHandle(long handle, int flags) throws PosixException { logEnter("openOsfHandle", "%d, %d", handle, flags); try { - return logExit("openOsfHandle", "%d", lib.openOsfHandle(delegate, handle, flags)); + return logExit("openOsfHandle", "%d", delegate.openOsfHandle(handle, flags)); } catch (PosixException e) { throw logException("openOsfHandle", e); } } - @ExportMessage - final int setMode(int fd, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int setMode(int fd, int mode) throws PosixException { logEnter("setMode", "%d, %d", fd, mode); try { - return logExit("setMode", "%d", lib.setMode(delegate, fd, mode)); + return logExit("setMode", "%d", delegate.setMode(fd, mode)); } catch (PosixException e) { throw logException("setMode", e); } } - @ExportMessage - final void msvcrtLocking(int fd, int mode, long nbytes, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { logEnter("msvcrtLocking", "%d, %d, %d", fd, mode, nbytes); try { - lib.msvcrtLocking(delegate, fd, mode, nbytes); + delegate.msvcrtLocking(fd, mode, nbytes); } catch (PosixException e) { throw logException("msvcrtLocking", e); } } - @ExportMessage - final int[] pipe( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int[] pipe() throws PosixException { logEnter("pipe", ""); try { - return logExit("pipe", "%s", lib.pipe(delegate)); + return logExit("pipe", "%s", delegate.pipe()); } catch (PosixException e) { throw logException("pipe", e); } } - @SuppressWarnings("all") - @ExportMessage - public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { logEnter("select", "%s %s %s %s", readfds, writefds, errorfds, timeout); try { - return logExit("select", "%s", lib.select(delegate, readfds, writefds, errorfds, timeout)); + return logExit("select", "%s", delegate.select(readfds, writefds, errorfds, timeout)); } catch (PosixException e) { throw logException("select", e); } } - @ExportMessage - public void poll(int[] fds, int[] events, int[] revents, int timeout, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { logEnter("poll", "%s %s %s", fds, events, timeout); try { - lib.poll(delegate, fds, events, revents, timeout); + delegate.poll(fds, events, revents, timeout); logExit("poll", "%s", revents); } catch (PosixException e) { throw logException("poll", e); } } - @ExportMessage - final long lseek(int fd, long offset, int how, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long lseek(int fd, long offset, int how) throws PosixException { logEnter("lseek", "%d, %d, %d", fd, offset, how); try { - return logExit("lseek", "%d", lib.lseek(delegate, fd, offset, how)); + return logExit("lseek", "%d", delegate.lseek(fd, offset, how)); } catch (PosixException e) { throw logException("lseek", e); } } - @ExportMessage - final void ftruncate(int fd, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void ftruncate(int fd, long length) throws PosixException { logEnter("ftruncate", "%d, %d", fd, length); try { - lib.ftruncate(delegate, fd, length); + delegate.ftruncate(fd, length); } catch (PosixException e) { throw logException("ftruncate", e); } } - @ExportMessage - final void truncate(Object path, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void truncate(Object path, long length) throws PosixException { logEnter("truncate", "%s, %d", path, length); try { - lib.truncate(delegate, path, length); + delegate.truncate(path, length); } catch (PosixException e) { throw logException("truncate", e); } } - @ExportMessage - final void fsync(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fsync(int fd) throws PosixException { logEnter("fsync", "%d", fd); try { - lib.fsync(delegate, fd); + delegate.fsync(fd); } catch (PosixException e) { throw logException("fsync", e); } } - @ExportMessage - final void flock(int fd, int operation, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void flock(int fd, int operation) throws PosixException { logEnter("flock", "%d %d", fd, operation); try { - lib.flock(delegate, fd, operation); + delegate.flock(fd, operation); } catch (PosixException e) { throw logException("flock", e); } } - @ExportMessage - final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { logEnter("fcntlLock", "%d %s %d %d %d %d", fd, blocking, lockType, whence, start, length); try { - lib.fcntlLock(delegate, fd, blocking, lockType, whence, start, length); + delegate.fcntlLock(fd, blocking, lockType, whence, start, length); } catch (PosixException e) { throw logException("fcntlLock", e); } } - @ExportMessage - final boolean getBlocking(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean getBlocking(int fd) throws PosixException { logEnter("getBlocking", "%d", fd); try { - return logExit("getBlocking", "%b", lib.getBlocking(delegate, fd)); + return logExit("getBlocking", "%b", delegate.getBlocking(fd)); } catch (PosixException e) { throw logException("getBlocking", e); } } - @ExportMessage - final void setBlocking(int fd, boolean blocking, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setBlocking(int fd, boolean blocking) throws PosixException { logEnter("setBlocking", "%d, %b", fd, blocking); try { - lib.setBlocking(delegate, fd, blocking); + delegate.setBlocking(fd, blocking); } catch (PosixException e) { throw logException("setBlocking", e); } } - @ExportMessage - final int[] getTerminalSize(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int[] getTerminalSize(int fd) throws PosixException { logEnter("getTerminalSize", "%d", fd); try { - return logExit("getTerminalSize", "%s", lib.getTerminalSize(delegate, fd)); + return logExit("getTerminalSize", "%s", delegate.getTerminalSize(fd)); } catch (PosixException e) { throw logException("getTerminalSize", e); } } - @ExportMessage - final long sysconf(int name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long sysconf(int name) throws PosixException { logEnter("sysconf", "%d", name); try { - return logExit("sysconf", "%s", lib.sysconf(delegate, name)); + return logExit("sysconf", "%s", delegate.sysconf(name)); } catch (PosixException e) { throw logException("sysconf", e); } } - @ExportMessage - final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { logEnter("fstatAt", "%d, %s, %b", dirFd, pathname, followSymlinks); try { - return logExit("fstatAt", "%s", lib.fstatat(delegate, dirFd, pathname, followSymlinks)); + return logExit("fstatAt", "%s", delegate.fstatat(dirFd, pathname, followSymlinks)); } catch (PosixException e) { throw logException("fstatAt", e); } } - @ExportMessage - final long[] fstat(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstat(int fd) throws PosixException { logEnter("fstat", "%d", fd); try { - return logExit("fstat", "%s", lib.fstat(delegate, fd)); + return logExit("fstat", "%s", delegate.fstat(fd)); } catch (PosixException e) { throw logException("fstat", e); } } - @ExportMessage - final long[] statvfs(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] statvfs(Object path) throws PosixException { logEnter("statvfs", "%s", path); try { - return logExit("statvfs", "%s", lib.statvfs(delegate, path)); + return logExit("statvfs", "%s", delegate.statvfs(path)); } catch (PosixException e) { throw logException("statvfs", e); } } - @ExportMessage - final long[] fstatvfs(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatvfs(int fd) throws PosixException { logEnter("fstatvfs", "%d", fd); try { - return logExit("fstatvfs", "%s", lib.fstatvfs(delegate, fd)); + return logExit("fstatvfs", "%s", delegate.fstatvfs(fd)); } catch (PosixException e) { throw logException("fstatvfs", e); } } - @ExportMessage - final Object[] uname( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object[] uname() throws PosixException { logEnter("uname", ""); try { - return logExit("uname", "%s", lib.uname(delegate)); + return logExit("uname", "%s", delegate.uname()); } catch (PosixException e) { throw logException("uname", e); } } - @ExportMessage - final WindowsVersion getWindowsVersion( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final WindowsVersion getWindowsVersion() throws PosixException { logEnter("getWindowsVersion", ""); try { - return logExit("getWindowsVersion", "%s", lib.getWindowsVersion(delegate)); + return logExit("getWindowsVersion", "%s", delegate.getWindowsVersion()); } catch (PosixException e) { throw logException("getWindowsVersion", e); } } - @ExportMessage - final void unlinkat(int dirFd, Object pathname, boolean rmdir, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { logEnter("unlinkAt", "%d, %s, %b", dirFd, pathname, rmdir); try { - lib.unlinkat(delegate, dirFd, pathname, rmdir); + delegate.unlinkat(dirFd, pathname, rmdir); } catch (PosixException e) { throw logException("unlinkAt", e); } } - @ExportMessage - final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { logEnter("linkAt", "%d, %s, %d, %s, %d", oldFdDir, oldPath, newFdDir, newPath, flags); try { - lib.linkat(delegate, oldFdDir, oldPath, newFdDir, newPath, flags); + delegate.linkat(oldFdDir, oldPath, newFdDir, newPath, flags); } catch (PosixException e) { throw logException("symlinkAt", e); } } - @ExportMessage - final void symlinkat(Object target, int linkpathDirFd, Object linkpath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { logEnter("symlinkAt", "%s, %d, %s", target, linkpathDirFd, linkpath); try { - lib.symlinkat(delegate, target, linkpathDirFd, linkpath); + delegate.symlinkat(target, linkpathDirFd, linkpath); } catch (PosixException e) { throw logException("symlinkAt", e); } } - @ExportMessage - final void mkdirat(int dirFd, Object pathname, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { logEnter("mkdirAt", "%d, %s, 0%o", dirFd, pathname, mode); try { - lib.mkdirat(delegate, dirFd, pathname, mode); + delegate.mkdirat(dirFd, pathname, mode); } catch (PosixException e) { throw logException("mkdirAt", e); } } - @ExportMessage - final Object getcwd( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object getcwd() throws PosixException { logEnter("getcwd", ""); try { - return logExit("getcwd", "%s", lib.getcwd(delegate)); + return logExit("getcwd", "%s", delegate.getcwd()); } catch (PosixException e) { throw logException("getcwd", e); } } - @ExportMessage - final void chdir(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void chdir(Object path) throws PosixException { logEnter("chdir", "%s", path); try { - lib.chdir(delegate, path); + delegate.chdir(path); } catch (PosixException e) { throw logException("chdir", e); } } - @ExportMessage - final void fchdir(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchdir(int fd) throws PosixException { logEnter("fchdir", "%d", fd); try { - lib.fchdir(delegate, fd); + delegate.fchdir(fd); } catch (PosixException e) { throw logException("fchdir", e); } } - @ExportMessage - final boolean isatty(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean isatty(int fd) { logEnter("isatty", "%d", fd); - return logExit("isatty", "%b", lib.isatty(delegate, fd)); + return logExit("isatty", "%b", delegate.isatty(fd)); } - @ExportMessage - final Object opendir(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object opendir(Object path) throws PosixException { logEnter("opendir", "%s", path); try { - return logExit("opendir", "%s", lib.opendir(delegate, path)); + return logExit("opendir", "%s", delegate.opendir(path)); } catch (PosixException e) { throw logException("opendir", e); } } - @ExportMessage - final Object fdopendir(int fd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object fdopendir(int fd) throws PosixException { logEnter("fdopendir", "%d", fd); try { - return logExit("fdopendir", "%s", lib.fdopendir(delegate, fd)); + return logExit("fdopendir", "%s", delegate.fdopendir(fd)); } catch (PosixException e) { throw logException("fdopendir", e); } } - @ExportMessage - final void closedir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void closedir(Object dirStream) throws PosixException { logEnter("closedir", "%s", dirStream); try { - lib.closedir(delegate, dirStream); + delegate.closedir(dirStream); } catch (PosixException e) { throw logException("closedir", e); } } - @ExportMessage - final Object readdir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object readdir(Object dirStream) throws PosixException { logEnter("readdir", "%s", dirStream); try { - return logExit("readdir", "%s", lib.readdir(delegate, dirStream)); + return logExit("readdir", "%s", delegate.readdir(dirStream)); } catch (PosixException e) { throw logException("readdir", e); } } - @ExportMessage - final void rewinddir(Object dirStream, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final void rewinddir(Object dirStream) { logEnter("rewinddir", "%s", dirStream); - lib.rewinddir(delegate, dirStream); + delegate.rewinddir(dirStream); } - @ExportMessage - final Object dirEntryGetName(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetName(Object dirEntry) throws PosixException { logEnter("dirEntryGetName", "%s", dirEntry); try { - return logExit("dirEntryGetName", "%s", lib.dirEntryGetName(delegate, dirEntry)); + return logExit("dirEntryGetName", "%s", delegate.dirEntryGetName(dirEntry)); } catch (PosixException e) { throw logException("dirEntryGetName", e); } } - @ExportMessage - final Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException { logEnter("dirEntryGetPath", "%s, %s", dirEntry, scandirPath); try { - return logExit("dirEntryGetPath", "%s", lib.dirEntryGetPath(delegate, dirEntry, scandirPath)); + return logExit("dirEntryGetPath", "%s", delegate.dirEntryGetPath(dirEntry, scandirPath)); } catch (PosixException e) { throw logException("dirEntryGetPath", e); } } - @ExportMessage - final long dirEntryGetInode(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long dirEntryGetInode(Object dirEntry) throws PosixException { logEnter("dirEntryGetInode", "%s", dirEntry); try { - return logExit("dirEntryGetInode", "%d", lib.dirEntryGetInode(delegate, dirEntry)); + return logExit("dirEntryGetInode", "%d", delegate.dirEntryGetInode(dirEntry)); } catch (PosixException e) { throw logException("dirEntryGetInode", e); } } - @ExportMessage - final int dirEntryGetType(Object dirEntry, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int dirEntryGetType(Object dirEntry) { logEnter("dirEntryGetType", "%s", dirEntry); - return logExit("dirEntryGetType", "%d", lib.dirEntryGetType(delegate, dirEntry)); + return logExit("dirEntryGetType", "%d", delegate.dirEntryGetType(dirEntry)); } - @ExportMessage - final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { logEnter("utimeNsAt", "%d, %s, %s, %b", dirFd, pathname, timespec, followSymlinks); try { - lib.utimensat(delegate, dirFd, pathname, timespec, followSymlinks); + delegate.utimensat(dirFd, pathname, timespec, followSymlinks); } catch (PosixException e) { throw logException("utimeNsAt", e); } } - @ExportMessage - final void futimens(int fd, long[] timespec, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void futimens(int fd, long[] timespec) throws PosixException { logEnter("futimeNs", "%d, %s", fd, timespec); try { - lib.futimens(delegate, fd, timespec); + delegate.futimens(fd, timespec); } catch (PosixException e) { throw logException("futimeNs", e); } } - @ExportMessage - final void futimes(int fd, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void futimes(int fd, Timeval[] timeval) throws PosixException { logEnter("futimes", "%d, %s", fd, timeval); try { - lib.futimes(delegate, fd, timeval); + delegate.futimes(fd, timeval); } catch (PosixException e) { throw logException("futimes", e); } } - @ExportMessage - final void lutimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void lutimes(Object filename, Timeval[] timeval) throws PosixException { logEnter("lutimes", "%s, %s", filename, timeval); try { - lib.lutimes(delegate, filename, timeval); + delegate.lutimes(filename, timeval); } catch (PosixException e) { throw logException("lutimes", e); } } - @ExportMessage - final void utimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void utimes(Object filename, Timeval[] timeval) throws PosixException { logEnter("utimes", "%s, %s", filename, timeval); try { - lib.utimes(delegate, filename, timeval); + delegate.utimes(filename, timeval); } catch (PosixException e) { throw logException("utimes", e); } } - @ExportMessage - final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { logEnter("renameAt", "%d, %s, %d, %s", oldDirFd, oldPath, newDirFd, newPath); try { - lib.renameat(delegate, oldDirFd, oldPath, newDirFd, newPath); + delegate.renameat(oldDirFd, oldPath, newDirFd, newPath); } catch (PosixException e) { throw logException("renameAt", e); } } - @ExportMessage - final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { logEnter("replaceAt", "%d, %s, %d, %s", oldDirFd, oldPath, newDirFd, newPath); try { - lib.replaceat(delegate, oldDirFd, oldPath, newDirFd, newPath); + delegate.replaceat(oldDirFd, oldPath, newDirFd, newPath); } catch (PosixException e) { throw logException("replaceAt", e); } } - @ExportMessage - final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { logEnter("faccessAt", "%d, %s, 0%o, %b, %b", dirFd, path, mode, effectiveIds, followSymlinks); try { - return logExit("faccessAt", "%b", lib.faccessat(delegate, dirFd, path, mode, effectiveIds, followSymlinks)); + return logExit("faccessAt", "%b", delegate.faccessat(dirFd, path, mode, effectiveIds, followSymlinks)); } catch (UnsupportedPosixFeatureException e) { throw logException("faccessAt", e); } } - @ExportMessage - final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { logEnter("fchmodat", "%d, %s, 0%o, %b", dirFd, path, mode, followSymlinks); try { - lib.fchmodat(delegate, dirFd, path, mode, followSymlinks); + delegate.fchmodat(dirFd, path, mode, followSymlinks); } catch (PosixException e) { throw logException("fchmodat", e); } } - @ExportMessage - final void fchmod(int fd, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmod(int fd, int mode) throws PosixException { logEnter("fchmod", "%d, 0%o", fd, mode); try { - lib.fchmod(delegate, fd, mode); + delegate.fchmod(fd, mode); } catch (PosixException e) { throw logException("fchmod", e); } } - @ExportMessage - final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { logEnter("fchownat", "%d, %s, %d, %d, %b", dirFd, path, owner, group, followSymlinks); try { - lib.fchownat(delegate, dirFd, path, owner, group, followSymlinks); + delegate.fchownat(dirFd, path, owner, group, followSymlinks); } catch (PosixException e) { throw logException("fchownat", e); } } - @ExportMessage - final void fchown(int fd, long owner, long group, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void fchown(int fd, long owner, long group) throws PosixException { logEnter("fchown", "%d, %d, %d", fd, owner, group); try { - lib.fchown(delegate, fd, owner, group); + delegate.fchown(fd, owner, group); } catch (PosixException e) { throw logException("fchown", e); } } - @ExportMessage - final Object readlinkat(int dirFd, Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object readlinkat(int dirFd, Object path) throws PosixException { logEnter("readlinkat", "%d, %s", dirFd, path); try { - return logExit("readlinkat", "%s", lib.readlinkat(delegate, dirFd, path)); + return logExit("readlinkat", "%s", delegate.readlinkat(dirFd, path)); } catch (PosixException e) { throw logException("readlinkat", e); } } - @ExportMessage - final void kill(long pid, int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void kill(long pid, int signal) throws PosixException { logEnter("kill", "%d, %d", pid, signal); try { - lib.kill(delegate, pid, signal); + delegate.kill(pid, signal); } catch (PosixException e) { throw logException("kill", e); } } - @ExportMessage - final void raise(int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void raise(int signal) throws PosixException { logEnter("raise", "%d", signal); try { - lib.raise(delegate, signal); + delegate.raise(signal); } catch (PosixException e) { throw logException("raise", e); } } - @ExportMessage - final int alarm(int seconds, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int alarm(int seconds) throws PosixException { logEnter("alarm", "%d", seconds); try { - return logExit("alarm", "%d", lib.alarm(delegate, seconds)); + return logExit("alarm", "%d", delegate.alarm(seconds)); } catch (PosixException e) { throw logException("alarm", e); } } - @ExportMessage - final Timeval[] getitimer(int which, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] getitimer(int which) throws PosixException { logEnter("getitimer", "%d", which); try { - return logExit("getitimer", "%s", lib.getitimer(delegate, which)); + return logExit("getitimer", "%s", delegate.getitimer(which)); } catch (PosixException e) { throw logException("getitimer", e); } } - @ExportMessage - final Timeval[] setitimer(int which, Timeval delay, Timeval interval, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { logEnter("setitimer", "%d, %s, %s", which, delay, interval); try { - return logExit("setitimer", "%s", lib.setitimer(delegate, which, delay, interval)); + return logExit("setitimer", "%s", delegate.setitimer(which, delay, interval)); } catch (PosixException e) { throw logException("setitimer", e); } } - @ExportMessage - final void signalSelf(int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void signalSelf(int signal) throws PosixException { logEnter("signalSelf", "%d", signal); try { - lib.signalSelf(delegate, signal); + delegate.signalSelf(signal); } catch (PosixException e) { throw logException("signalSelf", e); } } - @ExportMessage - final void killpg(long pgid, int signal, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void killpg(long pgid, int signal) throws PosixException { logEnter("killpg", "%d, %d", pgid, signal); try { - lib.killpg(delegate, pgid, signal); + delegate.killpg(pgid, signal); } catch (PosixException e) { throw logException("killpg", e); } } - @ExportMessage - public Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { logEnter("mmap", "%d, %d, %d, %d, %d, %s", length, prot, flags, fd, offset, tagname); try { - return logExit("mmap", "%s", lib.mmap(delegate, length, prot, flags, fd, offset, tagname)); + return logExit("mmap", "%s", delegate.mmap(location, length, prot, flags, fd, offset, tagname)); } catch (PosixException e) { throw logException("mmap", e); } } - @ExportMessage - final long[] waitpid(long pid, int options, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] waitpid(Node location, long pid, int options) throws PosixException { logEnter("waitpid", "%d, %d", pid, options); try { - return logExit("waitpid", "%s", lib.waitpid(delegate, pid, options)); + return logExit("waitpid", "%s", delegate.waitpid(location, pid, options)); } catch (PosixException e) { throw logException("waitpid", e); } } - @ExportMessage - public byte mmapReadByte(Object mmap, long index, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public byte mmapReadByte(Object mmap, long index) throws PosixException { logEnter("mmapReadByte", "%s, %d", mmap, index); try { - return logExit("mmapReadByte", "%s", lib.mmapReadByte(delegate, mmap, index)); + return logExit("mmapReadByte", "%s", delegate.mmapReadByte(mmap, index)); } catch (PosixException e) { throw logException("mmapReadByte", e); } } - @ExportMessage - public void mmapWriteByte(Object mmap, long index, byte value, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { logEnter("mmapWriteByte", "%s, %d, %d", mmap, index, value); try { - lib.mmapWriteByte(delegate, mmap, index, value); + delegate.mmapWriteByte(mmap, index, value); } catch (PosixException e) { throw logException("mmapWriteByte", e); } } - @ExportMessage - final boolean wcoredump(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wcoredump(int status) { logEnter("wcoredump", "%d", status); - return logExit("wcoredump", "%b", lib.wcoredump(delegate, status)); + return logExit("wcoredump", "%b", delegate.wcoredump(status)); } - @ExportMessage - final boolean wifcontinued(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifcontinued(int status) { logEnter("wifcontinued", "%d", status); - return logExit("wifcontinued", "%b", lib.wifcontinued(delegate, status)); + return logExit("wifcontinued", "%b", delegate.wifcontinued(status)); } - @ExportMessage - final boolean wifstopped(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifstopped(int status) { logEnter("wifstopped", "%d", status); - return logExit("wifstopped", "%b", lib.wifstopped(delegate, status)); + return logExit("wifstopped", "%b", delegate.wifstopped(status)); } - @ExportMessage - final boolean wifsignaled(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifsignaled(int status) { logEnter("wifsignaled", "%d", status); - return logExit("wifsignaled", "%b", lib.wifsignaled(delegate, status)); + return logExit("wifsignaled", "%b", delegate.wifsignaled(status)); } - @ExportMessage - final boolean wifexited(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final boolean wifexited(int status) { logEnter("wifexited", "%d", status); - return logExit("wifexited", "%b", lib.wifexited(delegate, status)); + return logExit("wifexited", "%b", delegate.wifexited(status)); } - @ExportMessage - final int wexitstatus(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wexitstatus(int status) { logEnter("wexitstatus", "%d", status); - return logExit("wexitstatus", "%d", lib.wexitstatus(delegate, status)); + return logExit("wexitstatus", "%d", delegate.wexitstatus(status)); } - @ExportMessage - final int wtermsig(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wtermsig(int status) { logEnter("wtermsig", "%d", status); - return logExit("wtermsig", "%d", lib.wtermsig(delegate, status)); + return logExit("wtermsig", "%d", delegate.wtermsig(status)); } - @ExportMessage - final int wstopsig(int status, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int wstopsig(int status) { logEnter("wstopsig", "%d", status); - return logExit("wstopsig", "%d", lib.wstopsig(delegate, status)); + return logExit("wstopsig", "%d", delegate.wstopsig(status)); } - @ExportMessage - final long getuid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final long getuid() { logEnter("getuid", ""); - return logExit("getuid", "%d", lib.getuid(delegate)); + return logExit("getuid", "%d", delegate.getuid()); } - @ExportMessage - final long geteuid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long geteuid() throws UnsupportedPosixFeatureException { logEnter("geteuid", ""); try { - return logExit("geteuid", "%d", lib.geteuid(delegate)); + return logExit("geteuid", "%d", delegate.geteuid()); } catch (UnsupportedPosixFeatureException e) { throw logException("geteuid", e); } } - @ExportMessage - final long getgid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final long getgid() { logEnter("getgid", ""); - return logExit("getgid", "%d", lib.getgid(delegate)); + return logExit("getgid", "%d", delegate.getgid()); } - @ExportMessage - final long getegid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getegid() throws UnsupportedPosixFeatureException { logEnter("getegid", ""); try { - return logExit("getegid", "%d", lib.getegid(delegate)); + return logExit("getegid", "%d", delegate.getegid()); } catch (UnsupportedPosixFeatureException e) { throw logException("getegid", e); } } - @ExportMessage - final long getppid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getppid() throws UnsupportedPosixFeatureException { logEnter("getppid", ""); try { - return logExit("getppid", "%d", lib.getppid(delegate)); + return logExit("getppid", "%d", delegate.getppid()); } catch (UnsupportedPosixFeatureException e) { throw logException("getppid", e); } } - @ExportMessage - final long getpgid(long pid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long getpgid(long pid) throws PosixException { logEnter("getpgid", "%d", pid); try { - return logExit("getpgid", "%d", lib.getpgid(delegate, pid)); + return logExit("getpgid", "%d", delegate.getpgid(pid)); } catch (PosixException e) { throw logException("getpgid", e); } } - @ExportMessage - final void setpgid(long pid, long pgid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setpgid(long pid, long pgid) throws PosixException { logEnter("setpgid", "%d, %d", pid, pgid); try { - lib.setpgid(delegate, pid, pgid); + delegate.setpgid(pid, pgid); } catch (PosixException e) { throw logException("setpgid", e); } } - @ExportMessage - final long getpgrp( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getpgrp() throws UnsupportedPosixFeatureException { logEnter("getpgrp", ""); try { - return logExit("getpgrp", "%d", lib.getpgrp(delegate)); + return logExit("getpgrp", "%d", delegate.getpgrp()); } catch (UnsupportedPosixFeatureException e) { throw logException("getpgrp", e); } } - @ExportMessage - final long getsid(long pid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long getsid(long pid) throws PosixException { logEnter("getsid", "%d", pid); try { - return logExit("getsid", "%d", lib.getsid(delegate, pid)); + return logExit("getsid", "%d", delegate.getsid(pid)); } catch (PosixException e) { throw logException("getsid", e); } } - @ExportMessage - final long setsid( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long setsid() throws PosixException { logEnter("setsid", ""); try { - return logExit("getsid", "%d", lib.setsid(delegate)); + return logExit("getsid", "%d", delegate.setsid()); } catch (PosixException e) { throw logException("setsid", e); } } - @ExportMessage - final long[] getgroups( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long[] getgroups() throws PosixException { logEnter("getgroups", ""); try { - return logExit("getgroups", "%s", lib.getgroups(delegate)); + return logExit("getgroups", "%s", delegate.getgroups()); } catch (PosixException e) { throw logException("getgroups", e); } } - @ExportMessage - final RusageResult getrusage(int who, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final RusageResult getrusage(int who) throws PosixException { logEnter("getrusage", "%d", who); try { - return logExit("getrusage", "%s", lib.getrusage(delegate, who)); + return logExit("getrusage", "%s", delegate.getrusage(who)); } catch (PosixException e) { throw logException("getrusage", e); } } - @ExportMessage - public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { logEnter("mmapReadBytes", "%s, %d, %d", mmap, index, length); try { - return logExit("mmapReadBytes", "%s", lib.mmapReadBytes(delegate, mmap, index, bytes, length)); + return logExit("mmapReadBytes", "%s", delegate.mmapReadBytes(mmap, index, bytes, length)); } catch (PosixException e) { throw logException("mmapReadBytes", e); } } - @ExportMessage - final OpenPtyResult openpty(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final OpenPtyResult openpty() throws PosixException { logEnter("openpty", ""); try { - return logExit("openpty", "%s", lib.openpty(delegate)); + return logExit("openpty", "%s", delegate.openpty()); } catch (PosixException e) { throw logException("openpty", e); } } - @ExportMessage - final TruffleString ctermid(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object ctermid() throws PosixException { logEnter("ctermid", ""); try { - return logExit("ctermid", "%s", lib.ctermid(delegate)); + return logExit("ctermid", "%s", delegate.ctermid()); } catch (PosixException e) { throw logException("ctermid", e); } } - @ExportMessage - final void setenv(Object name, Object value, boolean overwrite, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setenv(Object name, Object value, boolean overwrite) throws PosixException { logEnter("setenv", "%s, %s, %b", name, value, overwrite); try { - lib.setenv(delegate, name, value, overwrite); + delegate.setenv(name, value, overwrite); } catch (PosixException e) { throw logException("setenv", e); } } - @ExportMessage - final void unsetenv(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void unsetenv(Object name) throws PosixException { logEnter("unsetenv", "%s", name); try { - lib.unsetenv(delegate, name); + delegate.unsetenv(name); } catch (PosixException e) { throw logException("unsetenv", e); } } - @ExportMessage - public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { logEnter("mmapWriteBytes", "%s, %d, %d", mmap, index, length); try { - lib.mmapWriteBytes(delegate, mmap, index, bytes, length); + delegate.mmapWriteBytes(mmap, index, bytes, length); } catch (PosixException e) { throw logException("mmapWriteBytes", e); } } - @ExportMessage - final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, + int stderrWriteFd, + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { logEnter("forkExec", "%s, %s, %s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %b, %b, %b, %d, %s, %b", executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); try { - return logExit("forkExec", "%d", lib.forkExec(delegate, executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, + return logExit("forkExec", "%d", delegate.forkExec(executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork)); } catch (PosixException e) { throw logException("forkExec", e); } } - @ExportMessage - public void mmapFlush(Object mmap, long offset, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapFlush(Object mmap, long offset, long length) throws PosixException { logEnter("mmapFlush", "%s, %d, %d", mmap, offset, length); try { - lib.mmapFlush(delegate, mmap, offset, length); + delegate.mmapFlush(mmap, offset, length); } catch (PosixException e) { throw logException("mmapFlush", e); } } - @ExportMessage - public long mmapGetPointer(Object mmap, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException { logEnter("mmapGetPointer", "%s", mmap); try { - return lib.mmapGetPointer(delegate, mmap); + return delegate.mmapGetPointer(mmap); } catch (UnsupportedPosixFeatureException e) { throw logException("mmapGetPointer", e); } } - @ExportMessage - final void execv(Object pathname, Object[] args, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void execv(Object pathname, Object[] args) throws PosixException { logEnter("execv", "%s, %s", pathname, args); try { - lib.execv(delegate, pathname, args); + delegate.execv(pathname, args); } catch (PosixException e) { throw logException("execv", e); } } - @ExportMessage - public void mmapUnmap(Object mmap, long length, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public void mmapUnmap(Object mmap, long length) throws PosixException { logEnter("mmapUnmap", "%s %d", mmap, length); try { - lib.mmapUnmap(delegate, mmap, length); + delegate.mmapUnmap(mmap, length); } catch (PosixException e) { throw logException("mmapUnmap", e); } } - @ExportMessage - public PwdResult getpwuid(long uid, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwuid(long uid) throws PosixException { logEnter("getpwuid", "%d", uid); try { - return logExit("getpwuid", "%s", lib.getpwuid(delegate, uid)); + return logExit("getpwuid", "%s", delegate.getpwuid(uid)); } catch (PosixException e) { throw logException("getpwuid", e); } } - @ExportMessage - public PwdResult getpwnam(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwnam(Object name) throws PosixException { logEnter("getpwnam", "%s", name); try { - return logExit("getpwnam", "%s", lib.getpwnam(delegate, name)); + return logExit("getpwnam", "%s", delegate.getpwnam(name)); } catch (PosixException e) { throw logException("getpwnam", e); } } - @SuppressWarnings("static-method") - @ExportMessage - public boolean hasGetpwentries(@CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return logExit("hasGetpwentries", "%b", lib.hasGetpwentries(delegate)); + @Override + @TruffleBoundary + public boolean hasGetpwentries() { + return logExit("hasGetpwentries", "%b", delegate.hasGetpwentries()); } - @ExportMessage - public PwdResult[] getpwentries( - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult[] getpwentries() throws PosixException { logEnter("getpwentries", ""); try { - return logExit("getpwentries", "%s", lib.getpwentries(delegate)); + return logExit("getpwentries", "%s", delegate.getpwentries()); } catch (PosixException e) { throw logException("getpwentries", e); } } - @ExportMessage - final int ioctlBytes(int fd, long request, byte[] arg, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { logEnter("ioctl", "%d %d %s", fd, request, arg); try { - return logExit("ioctl", "%d", lib.ioctlBytes(delegate, fd, request, arg)); + return logExit("ioctl", "%d", delegate.ioctlBytes(fd, request, arg)); } catch (PosixException e) { throw logException("ioctl", e); } } - @ExportMessage - final int ioctlInt(int fd, long request, int arg, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlInt(int fd, long request, int arg) throws PosixException { logEnter("ioctl", "%d %d %d", fd, request, arg); try { - return logExit("ioctl", "%d", lib.ioctlInt(delegate, fd, request, arg)); + return logExit("ioctl", "%d", delegate.ioctlInt(fd, request, arg)); } catch (PosixException e) { throw logException("ioctl", e); } } - @ExportMessage - final int system(Object command, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int system(Object command) { logEnter("system", "%s", command); - return logExit("system", "%d", lib.system(delegate, command)); + return logExit("system", "%d", delegate.system(command)); } - @ExportMessage - final int socket(int domain, int type, int protocol, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int socket(int domain, int type, int protocol) throws PosixException { logEnter("socket", "%d, %d, %d", domain, type, protocol); try { - return logExit("socket", "%d", lib.socket(delegate, domain, type, protocol)); + return logExit("socket", "%d", delegate.socket(domain, type, protocol)); } catch (PosixException e) { throw logException("socket", e); } } - @ExportMessage - final AcceptResult accept(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final AcceptResult accept(int sockfd) throws PosixException { logEnter("accept", "%d", sockfd); try { - return logExit("accept", "%s", lib.accept(delegate, sockfd)); + return logExit("accept", "%s", delegate.accept(sockfd)); } catch (PosixException e) { throw logException("accept", e); } } - @ExportMessage - final void bind(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void bind(int sockfd, UniversalSockAddr addr) throws PosixException { logEnter("bind", "%d, %s", sockfd, addr); try { - lib.bind(delegate, sockfd, addr); + delegate.bind(sockfd, addr); } catch (PosixException e) { throw logException("bind", e); } } - @ExportMessage - final void connect(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void connect(int sockfd, UniversalSockAddr addr) throws PosixException { logEnter("connect", "%d, %s", sockfd, addr); try { - lib.connect(delegate, sockfd, addr); + delegate.connect(sockfd, addr); } catch (PosixException e) { throw logException("connect", e); } } - @ExportMessage - final void listen(int sockfd, int backlog, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void listen(int sockfd, int backlog) throws PosixException { logEnter("listen", "%d, %d", sockfd, backlog); try { - lib.listen(delegate, sockfd, backlog); + delegate.listen(sockfd, backlog); } catch (PosixException e) { throw logException("listen", e); } } - @ExportMessage - final UniversalSockAddr getpeername(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getpeername(int sockfd) throws PosixException { logEnter("getpeername", "%d", sockfd); try { - return logExit("getpeername", "%s", lib.getpeername(delegate, sockfd)); + return logExit("getpeername", "%s", delegate.getpeername(sockfd)); } catch (PosixException e) { throw logException("getpeername", e); } } - @ExportMessage - final UniversalSockAddr getsockname(int sockfd, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getsockname(int sockfd) throws PosixException { logEnter("getsockname", "%d", sockfd); try { - return logExit("getsockname", "%s", lib.getsockname(delegate, sockfd)); + return logExit("getsockname", "%s", delegate.getsockname(sockfd)); } catch (PosixException e) { throw logException("getsockname", e); } } - @ExportMessage - final int send(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("send", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("send", "%d", lib.send(delegate, sockfd, buf, offset, len, flags)); + return logExit("send", "%d", delegate.send(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("send", e); } } - @ExportMessage - final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { logEnter("sendto", "%d, %d, %d, %d, %s", sockfd, offset, len, flags, destAddr); try { - return logExit("sendto", "%d", lib.sendto(delegate, sockfd, buf, offset, len, flags, destAddr)); + return logExit("sendto", "%d", delegate.sendto(sockfd, buf, offset, len, flags, destAddr)); } catch (PosixException e) { throw logException("sendto", e); } } - @ExportMessage - final int recv(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("recv", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("recv", "%d", lib.recv(delegate, sockfd, buf, offset, len, flags)); + return logExit("recv", "%d", delegate.recv(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("recv", e); } } - @ExportMessage - final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { logEnter("recvfrom", "%d, %d, %d, %d", sockfd, offset, len, flags); try { - return logExit("recvfrom", "%s", lib.recvfrom(delegate, sockfd, buf, offset, len, flags)); + return logExit("recvfrom", "%s", delegate.recvfrom(sockfd, buf, offset, len, flags)); } catch (PosixException e) { throw logException("recvfrom", e); } } - @ExportMessage - final void shutdown(int sockfd, int how, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shutdown(int sockfd, int how) throws PosixException { logEnter("shutdown", "%d, %d", sockfd, how); try { - lib.shutdown(delegate, sockfd, how); + delegate.shutdown(sockfd, how); } catch (PosixException e) { throw logException("shutdown", e); } } - @ExportMessage - final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { logEnter("getsockopt", "%d, %d, %d, %s, %d", sockfd, level, optname, optval, optlen); try { - return logExit("getsockopt", "%d", lib.getsockopt(delegate, sockfd, level, optname, optval, optlen)); + return logExit("getsockopt", "%d", delegate.getsockopt(sockfd, level, optname, optval, optlen)); } catch (PosixException e) { throw logException("getsockopt", e); } } - @ExportMessage - final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { logEnter("setsockopt", "%d, %d, %d, %s, %d", sockfd, level, optname, optval, optlen); try { - lib.setsockopt(delegate, sockfd, level, optname, optval, optlen); + delegate.setsockopt(sockfd, level, optname, optval, optlen); } catch (PosixException e) { throw logException("setsockopt", e); } } - @ExportMessage - final int inet_addr(Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final int inet_addr(Object src) { logEnter("inet_addr", "%s", src); - return logExit("inet_addr", "%d", lib.inet_addr(delegate, src)); + return logExit("inet_addr", "%d", delegate.inet_addr(src)); } - @ExportMessage - final int inet_aton(Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws InvalidAddressException { + @Override + @TruffleBoundary + public final int inet_aton(Object src) throws InvalidAddressException { logEnter("inet_aton", "%s", src); try { - return logExit("inet_aton", "%d", lib.inet_aton(delegate, src)); + return logExit("inet_aton", "%d", delegate.inet_aton(src)); } catch (InvalidAddressException e) { throw logException("inet_aton", e); } } - @ExportMessage - final Object inet_ntoa(int address, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final Object inet_ntoa(int address) { logEnter("inet_ntoa", "%d", address); - return logExit("inet_ntoa", "%s", lib.inet_ntoa(delegate, address)); + return logExit("inet_ntoa", "%s", delegate.inet_ntoa(address)); } - @ExportMessage - final byte[] inet_pton(int family, Object src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException, InvalidAddressException { + @Override + @TruffleBoundary + public final byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { logEnter("inet_pton", "%d, %s", family, src); try { - return logExit("inet_pton", "%s", lib.inet_pton(delegate, family, src)); + return logExit("inet_pton", "%s", delegate.inet_pton(family, src)); } catch (PosixException e) { throw logException("inet_pton", e); } catch (InvalidAddressException e) { @@ -1499,33 +1515,34 @@ final byte[] inet_pton(int family, Object src, } } - @ExportMessage - final Object inet_ntop(int family, byte[] src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object inet_ntop(int family, byte[] src) throws PosixException { logEnter("inet_ntop", "%d, %s", family, src); try { - return logExit("inet_ntop", "%s", lib.inet_ntop(delegate, family, src)); + return logExit("inet_ntop", "%s", delegate.inet_ntop(family, src)); } catch (PosixException e) { throw logException("inet_ntop", e); } } - @ExportMessage - final Object gethostname(@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final Object gethostname() throws PosixException { logEnter("gethostname", ""); try { - return logExit("gethostname", "%s", lib.gethostname(delegate)); + return logExit("gethostname", "%s", delegate.gethostname()); } catch (PosixException e) { throw logException("gethostname", e); } } - @ExportMessage - final Object[] getnameinfo(UniversalSockAddr addr, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { logEnter("getnameinfo", "%s, %d", addr, flags); try { - return logExit("getnameinfo", "%s", lib.getnameinfo(delegate, addr, flags)); + return logExit("getnameinfo", "%s", delegate.getnameinfo(addr, flags)); } catch (UnsupportedPosixFeatureException e) { throw logException("getnameinfo", e); } catch (GetAddrInfoException e) { @@ -1533,12 +1550,12 @@ final Object[] getnameinfo(UniversalSockAddr addr, int flags, } } - @ExportMessage - final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { logEnter("getaddrinfo", "%s, %s, %d, %d, %d, %d", node, service, family, sockType, protocol, flags); try { - return logExit("getaddrinfo", "%s", lib.getaddrinfo(delegate, node, service, family, sockType, protocol, flags)); + return logExit("getaddrinfo", "%s", delegate.getaddrinfo(node, service, family, sockType, protocol, flags)); } catch (UnsupportedPosixFeatureException e) { throw logException("getaddrinfo", e); } catch (GetAddrInfoException e) { @@ -1546,136 +1563,136 @@ final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int so } } - @ExportMessage - final long semOpen(Object name, int openFlags, int mode, int value, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { logEnter("semOpen", "%s %d %d %d", name, openFlags, mode, value); try { - return logExit("semOpen", "0x%x", lib.semOpen(delegate, name, openFlags, mode, value)); + return logExit("semOpen", "0x%x", delegate.semOpen(name, openFlags, mode, value)); } catch (PosixException e) { throw logException("semOpen", e); } } - @ExportMessage - final void semClose(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semClose(long handle) throws PosixException { logEnter("semClose", "0x%x", handle); try { - lib.semClose(delegate, handle); + delegate.semClose(handle); } catch (PosixException e) { throw logException("semClose", e); } } - @ExportMessage - final void semUnlink(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semUnlink(Object name) throws PosixException { logEnter("semUnlink", "%s", name); try { - lib.semUnlink(delegate, name); + delegate.semUnlink(name); } catch (PosixException e) { throw logException("semUnlink", e); } } - @ExportMessage - final int shmOpen(Object name, int openFlags, int mode, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int shmOpen(Object name, int openFlags, int mode) throws PosixException { logEnter("shmOpen", "%s %d %d", name, openFlags, mode); try { - return logExit("shmOpen", "%d", lib.shmOpen(delegate, name, openFlags, mode)); + return logExit("shmOpen", "%d", delegate.shmOpen(name, openFlags, mode)); } catch (PosixException e) { throw logException("shmOpen", e); } } - @ExportMessage - final void shmUnlink(Object name, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shmUnlink(Object name) throws PosixException { logEnter("shmUnlink", "%s", name); try { - lib.shmUnlink(delegate, name); + delegate.shmUnlink(name); } catch (PosixException e) { throw logException("shmUnlink", e); } } - @ExportMessage - final int semGetValue(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int semGetValue(long handle) throws PosixException { logEnter("semGetValue", "0x%x", handle); try { - return logExit("semGetValue", "%d", lib.semGetValue(delegate, handle)); + return logExit("semGetValue", "%d", delegate.semGetValue(handle)); } catch (PosixException e) { throw logException("semGetValue", e); } } - @ExportMessage - final void semPost(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semPost(long handle) throws PosixException { logEnter("semPost", "0x%x", handle); try { - lib.semPost(delegate, handle); + delegate.semPost(handle); } catch (PosixException e) { throw logException("semPost", e); } } - @ExportMessage - final void semWait(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semWait(long handle) throws PosixException { logEnter("semWait", "0x%x", handle); try { - lib.semWait(delegate, handle); + delegate.semWait(handle); } catch (PosixException e) { throw logException("semWait", e); } } - @ExportMessage - final boolean semTryWait(long handle, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTryWait(long handle) throws PosixException { logEnter("semTryWait", "0x%x", handle); try { - return logExit("semTryWait", "%b", lib.semTryWait(delegate, handle)); + return logExit("semTryWait", "%b", delegate.semTryWait(handle)); } catch (PosixException e) { throw logException("semTryWait", e); } } - @ExportMessage - final boolean semTimedWait(long handle, long deadlineNs, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { logEnter("semTimedWait", "0x%x %d", handle, deadlineNs); try { - return logExit("semTimedWait", "%b", lib.semTimedWait(delegate, handle, deadlineNs)); + return logExit("semTimedWait", "%b", delegate.semTimedWait(location, handle, deadlineNs)); } catch (PosixException e) { throw logException("semTimedWait", e); } } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { logEnter("createUniversalSockAddrInet4", "%s", src); - return logExit("createUniversalSockAddrInet4", "%s", lib.createUniversalSockAddrInet4(delegate, src)); + return logExit("createUniversalSockAddrInet4", "%s", delegate.createUniversalSockAddrInet4(src)); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { logEnter("createUniversalSockAddrInet6", "%s", src); - return logExit("createUniversalSockAddrInet6", "%s", lib.createUniversalSockAddrInet6(delegate, src)); + return logExit("createUniversalSockAddrInet6", "%s", delegate.createUniversalSockAddrInet6(src)); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { logEnter("createUniversalSockAddrUnix", "%s", src); try { - return logExit("createUniversalSockAddrUnix", "%s", lib.createUniversalSockAddrUnix(delegate, src)); + return logExit("createUniversalSockAddrUnix", "%s", delegate.createUniversalSockAddrUnix(src)); } catch (UnsupportedPosixFeatureException e) { throw logException("createUniversalSockAddrUnix", e); } catch (InvalidUnixSocketPathException e) { @@ -1683,62 +1700,10 @@ final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, } } - @ExportMessage - final Object createPathFromString(TruffleString path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - logEnter(Level.FINEST, "createPathFromString", "%s", path); - return logExit(Level.FINEST, "createPathFromString", "%s", lib.createPathFromString(delegate, path)); - } - - @ExportMessage - final Object createPathFromBytes(byte[] path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - logEnter(Level.FINEST, "createPathFromBytes", "%s", path); - return logExit(Level.FINEST, "createPathFromBytes", "%s", lib.createPathFromBytes(delegate, path)); - } - - @ExportMessage - final TruffleString getPathAsString(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - logEnter(Level.FINEST, "getPathAsString", "%s", path); - return logExit(Level.FINEST, "getPathAsString", "%s", lib.getPathAsString(delegate, path)); - } - - @ExportMessage - final Buffer getPathAsBytes(Object path, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - logEnter(Level.FINEST, "getPathAsBytes", "%s", path); - return logExit(Level.FINEST, "getPathAsBytes", "%s", lib.getPathAsBytes(delegate, path)); - } - - @ExportMessage - final Object createCStringFromString(TruffleString string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createCStringFromString(delegate, string); - } - - @ExportMessage - final Object createCStringFromBytes(byte[] bytes, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createCStringFromBytes(delegate, bytes); - } - - @ExportMessage - final Object createWideStringFromString(TruffleString string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.createWideStringFromString(delegate, string); - } - - @ExportMessage - final TruffleString getCStringAsString(Object string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.getCStringAsString(delegate, string); - } - - @ExportMessage - final Buffer getCStringAsBytes(Object string, - @CachedLibrary("this.delegate") PosixSupportLibrary lib) { - return lib.getCStringAsBytes(delegate, string); + @Override + @TruffleBoundary + public final Object createCStringFromBytes(byte[] bytes) { + return delegate.createCStringFromBytes(bytes); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java index 0653be98fe..b7da1d6cc2 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java @@ -59,8 +59,8 @@ import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT; import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY; import static com.oracle.graal.python.runtime.NativePosixConstants.OFFSETOF_STRUCT_SOCKADDR_UN_SUN_PATH; -import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_POLLFD; +import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_IN6; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_SA_FAMILY; import static com.oracle.graal.python.runtime.NativePosixConstants.SIZEOF_STRUCT_SOCKADDR_STORAGE; @@ -78,7 +78,6 @@ import static com.oracle.graal.python.runtime.PosixConstants.PATH_MAX; import static com.oracle.graal.python.runtime.PosixConstants.WNOHANG; import static com.oracle.graal.python.runtime.PosixConstants._POSIX_HOST_NAME_MAX; -import static com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.NULLPTR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR; import static com.oracle.graal.python.util.PythonUtils.ARRAY_ACCESSOR_BE; @@ -99,36 +98,12 @@ import com.oracle.graal.python.annotations.PythonOS; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.lib.PyUnicodeEncodeFSDefaultNode; -import com.oracle.graal.python.lib.PyUnicodeFSDecoderNode; import com.oracle.graal.python.nodes.PRaiseNode; import com.oracle.graal.python.nodes.call.CallNode; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursorLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixErrnoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddrLibrary; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.nativeaccess.NativeLibrary; import com.oracle.graal.python.runtime.nativeaccess.NativeLibraryLoadException; import com.oracle.graal.python.runtime.nativeaccess.NativeMemory; -import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.graal.python.util.OverflowException; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.ArrayUtils; @@ -139,17 +114,8 @@ import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.TruffleLogger; import com.oracle.truffle.api.TruffleSafepoint; -import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Exclusive; -import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.strings.AbstractTruffleString; -import com.oracle.truffle.api.strings.InternalByteArray; import com.oracle.truffle.api.strings.TranscodingErrorHandler; import com.oracle.truffle.api.strings.TruffleString; @@ -163,8 +129,20 @@ * functions store errno in a C thread-local only when the POSIX return value indicates an error. This * avoids unconditional FFM call-state capture on the hot POSIX path. */ -@ExportLibrary(PosixSupportLibrary.class) public final class NativePosixSupport extends PosixSupport { + public static final class NativePwdResult extends PwdResult { + public final Buffer name; + public final Buffer dir; + public final Buffer shell; + + public NativePwdResult(Buffer name, long uid, long gid, Buffer dir, Buffer shell) { + super(uid, gid); + this.name = name; + this.dir = dir; + this.shell = shell; + } + } + private static final String SUPPORTING_NATIVE_LIB_NAME = "posix"; private static final int UNAME_BUF_LENGTH = 256; private static final int DIRENT_NAME_BUF_LENGTH = 256; @@ -231,6 +209,12 @@ abstract static class PosixNativeFunctionInvoker { @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) abstract long call_write(int fd, long buf, long count); + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) + abstract int call_get_windows_console_type(int fd); + + @DowncallSignature(returnType = SINT64, argumentTypes = {SINT32, POINTER, SINT64}) + abstract long call_write_windows_console(int fd, long buf, long count); + @DowncallSignature(returnType = SINT32, argumentTypes = {SINT32}) abstract int call_dup(int fd); @@ -708,15 +692,15 @@ public void setEnv(Env env) { } } - @ExportMessage + @Override + @TruffleBoundary public TruffleString getBackend() { return nativeBackend; } - @ExportMessage - public TruffleString strerror(int errorCode, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { + @Override + @TruffleBoundary + public TruffleString strerror(int errorCode) { // From man pages: The GNU C Library uses a buffer of 1024 characters for strerror(). // This buffer size therefore should be sufficient to avoid an ERANGE error when calling // strerror_r(). @@ -724,23 +708,28 @@ public TruffleString strerror(int errorCode, try { posixNativeFunctionInvoker.call_strerror(errorCode, buf, STRERROR_BUF_LENGTH); // TODO PyUnicode_DecodeLocale - return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, buf); + TruffleString message = NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(buf); + message.toJavaStringUncached(); + return message; } finally { NativeMemory.free(buf); } } - @ExportMessage + @Override + @TruffleBoundary public long getpid() { return posixNativeFunctionInvoker.call_getpid(); } - @ExportMessage + @Override + @TruffleBoundary public int umask(int mask) { return posixNativeFunctionInvoker.call_umask(mask); } - @ExportMessage + @Override + @TruffleBoundary public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -754,7 +743,8 @@ public int openat(int dirFd, Object pathname, int flags, int mode) throws PosixE } } - @ExportMessage + @Override + @TruffleBoundary public int close(int fd) throws PosixException { final int rv = posixNativeFunctionInvoker.call_close(fd); if (rv < 0) { @@ -763,7 +753,8 @@ public int close(int fd) throws PosixException { return rv; } - @ExportMessage + @Override + @TruffleBoundary public Buffer read(int fd, long length) throws PosixException { long count = Math.min(length, MAX_READ); Buffer buffer = Buffer.allocate(count); @@ -780,7 +771,8 @@ public Buffer read(int fd, long length) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long write(int fd, Buffer data) throws PosixException { long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); try { @@ -795,7 +787,30 @@ public long write(int fd, Buffer data) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary + public int getWindowsConsoleType(int fd) { + return posixNativeFunctionInvoker.call_get_windows_console_type(fd); + } + + @Override + @TruffleBoundary + public long writeWindowsConsole(int fd, Buffer data) throws PosixException { + long nativeBuffer = NativeMemory.mallocByteArrayOrNull(data.length); + try { + NativeMemory.writeByteArrayElements(nativeBuffer, 0, data.data, 0, (int) data.length); + long n = posixNativeFunctionInvoker.call_write_windows_console(fd, nativeBuffer, data.length); + if (n < 0) { + throw getErrnoAndThrowPosixException(); + } + return n; + } finally { + NativeMemory.free(nativeBuffer); + } + } + + @Override + @TruffleBoundary public int dup(int fd) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup(fd); if (newFd < 0) { @@ -804,7 +819,8 @@ public int dup(int fd) throws PosixException { return newFd; } - @ExportMessage + @Override + @TruffleBoundary public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { int newFd = posixNativeFunctionInvoker.call_dup2(fd, fd2, inheritable ? 1 : 0); if (newFd < 0) { @@ -813,7 +829,8 @@ public int dup2(int fd, int fd2, boolean inheritable) throws PosixException { return newFd; } - @ExportMessage + @Override + @TruffleBoundary public boolean getInheritable(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_inheritable(fd); if (result < 0) { @@ -822,14 +839,16 @@ public boolean getInheritable(int fd) throws PosixException { return result != 0; } - @ExportMessage + @Override + @TruffleBoundary public void setInheritable(int fd, boolean inheritable) throws PosixException { if (posixNativeFunctionInvoker.set_inheritable(fd, inheritable ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage + @Override + @TruffleBoundary public long getOsfHandle(int fd) throws PosixException { long nativeOut = NativeMemory.mallocLongArray(1); try { @@ -842,7 +861,8 @@ public long getOsfHandle(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int openOsfHandle(long handle, int flags) throws PosixException { int fd = posixNativeFunctionInvoker.call_open_osfhandle(handle, flags); if (fd < 0) { @@ -851,7 +871,8 @@ public int openOsfHandle(long handle, int flags) throws PosixException { return fd; } - @ExportMessage + @Override + @TruffleBoundary public int setMode(int fd, int mode) throws PosixException { int previousMode = posixNativeFunctionInvoker.call_setmode(fd, mode); if (previousMode < 0) { @@ -860,14 +881,16 @@ public int setMode(int fd, int mode) throws PosixException { return previousMode; } - @ExportMessage + @Override + @TruffleBoundary public void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { if (posixNativeFunctionInvoker.call_msvcrt_locking(fd, mode, nbytes) != 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage + @Override + @TruffleBoundary public int[] pipe() throws PosixException { int[] fds = new int[2]; long nativeFds = NativeMemory.mallocIntArray(fds.length); @@ -882,7 +905,8 @@ public int[] pipe() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { int largestFD = findMax(readfds, -1); largestFD = findMax(writefds, largestFD); @@ -939,7 +963,8 @@ private static boolean[] selectFillInResult(int[] fds, byte[] selected, int sele private static int findMax(int[] items, int currentMax) { int max = currentMax; - for (int item : items) { + for (int i = 0; i < items.length; i++) { + int item = items[i]; if (item > max) { max = item; } @@ -947,7 +972,8 @@ private static int findMax(int[] items, int currentMax) { return max; } - @ExportMessage + @Override + @TruffleBoundary public void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { assert fds.length == events.length && fds.length == revents.length; int count = fds.length; @@ -978,7 +1004,8 @@ public void poll(int[] fds, int[] events, int[] revents, int timeout) throws Pos } } - @ExportMessage + @Override + @TruffleBoundary public long lseek(int fd, long offset, int how) throws PosixException { long res = posixNativeFunctionInvoker.call_lseek(fd, offset, how); if (res < 0) { @@ -987,7 +1014,8 @@ public long lseek(int fd, long offset, int how) throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public void ftruncate(int fd, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_ftruncate(fd, length); if (res != 0) { @@ -995,7 +1023,8 @@ public void ftruncate(int fd, long length) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void truncate(Object path, long length) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1008,7 +1037,8 @@ public void truncate(Object path, long length) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fsync(int fd) throws PosixException { int res = posixNativeFunctionInvoker.call_fsync(fd); if (res != 0) { @@ -1016,23 +1046,26 @@ public void fsync(int fd) throws PosixException { } } - @ExportMessage - void flock(int fd, int operation) throws PosixException { + @Override + @TruffleBoundary + public void flock(int fd, int operation) throws PosixException { int res = posixNativeFunctionInvoker.call_flock(fd, operation); if (res != 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { + @Override + @TruffleBoundary + public void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { int res = posixNativeFunctionInvoker.call_fcntl_lock(fd, blocking ? 1 : 0, lockType, whence, start, length); if (res != 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage + @Override + @TruffleBoundary public boolean getBlocking(int fd) throws PosixException { int result = posixNativeFunctionInvoker.get_blocking(fd); if (result < 0) { @@ -1041,14 +1074,16 @@ public boolean getBlocking(int fd) throws PosixException { return result != 0; } - @ExportMessage + @Override + @TruffleBoundary public void setBlocking(int fd, boolean blocking) throws PosixException { if (posixNativeFunctionInvoker.set_blocking(fd, blocking ? 1 : 0) < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage + @Override + @TruffleBoundary public int[] getTerminalSize(int fd) throws PosixException { int[] size = new int[2]; long nativeSize = NativeMemory.mallocIntArray(size.length); @@ -1063,7 +1098,8 @@ public int[] getTerminalSize(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long sysconf(int name) throws PosixException { long result = posixNativeFunctionInvoker.call_sysconf(name); if (result == Long.MIN_VALUE) { @@ -1072,7 +1108,8 @@ public long sysconf(int name) throws PosixException { return result; } - @ExportMessage + @Override + @TruffleBoundary public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { long[] out = new long[13]; long nativeOut = NULLPTR; @@ -1092,7 +1129,8 @@ public long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws } } - @ExportMessage + @Override + @TruffleBoundary public long[] fstat(int fd) throws PosixException { long[] out = new long[13]; long nativeOut = NativeMemory.mallocLongArray(out.length); @@ -1108,7 +1146,8 @@ public long[] fstat(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long[] statvfs(Object path) throws PosixException { long[] out = new long[11]; long nativeOut = NULLPTR; @@ -1128,7 +1167,8 @@ public long[] statvfs(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long[] fstatvfs(int fd) throws PosixException { long[] out = new long[11]; long nativeOut = NativeMemory.mallocLongArray(out.length); @@ -1144,10 +1184,9 @@ public long[] fstatvfs(int fd) throws PosixException { } } - @ExportMessage - public Object[] uname( - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws PosixException { + @Override + @TruffleBoundary + public Object[] uname() throws PosixException { long sysPtr = NULLPTR; long nodePtr = NULLPTR; long relPtr = NULLPTR; @@ -1165,11 +1204,11 @@ public Object[] uname( } return new Object[]{ // TODO PyUnicode_DecodeFSDefault - zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, sysPtr), - zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nodePtr), - zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, relPtr), - zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, verPtr), - zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, machinePtr) + NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(sysPtr), + NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(nodePtr), + NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(relPtr), + NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(verPtr), + NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.executeUncached(machinePtr) }; } finally { NativeMemory.free(machinePtr); @@ -1180,7 +1219,7 @@ public Object[] uname( } } - @ExportMessage + @Override @TruffleBoundary public WindowsVersion getWindowsVersion() throws PosixException { long out = NativeMemory.mallocIntArray(11); @@ -1201,7 +1240,8 @@ public WindowsVersion getWindowsVersion() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -1214,7 +1254,8 @@ public void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixExce } } - @ExportMessage + @Override + @TruffleBoundary public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; @@ -1231,7 +1272,8 @@ public void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, i } } - @ExportMessage + @Override + @TruffleBoundary public void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { long targetPtr = NULLPTR; long linkpathPtr = NULLPTR; @@ -1248,7 +1290,8 @@ public void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws } } - @ExportMessage + @Override + @TruffleBoundary public void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { long pathnamePtr = pathToNativeCString(pathname); try { @@ -1261,7 +1304,8 @@ public void mkdirat(int dirFd, Object pathname, int mode) throws PosixException } } - @ExportMessage + @Override + @TruffleBoundary public Object getcwd() throws PosixException { for (int bufLen = 1024;; bufLen += 1024) { int byteLen = WINDOWS ? bufLen * 2 : bufLen; @@ -1286,7 +1330,8 @@ public Object getcwd() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void chdir(Object path) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1299,7 +1344,8 @@ public void chdir(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fchdir(int fd) throws PosixException { int result = posixNativeFunctionInvoker.call_fchdir(fd); if (result != 0) { @@ -1307,12 +1353,14 @@ public void fchdir(int fd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public boolean isatty(int fd) { return posixNativeFunctionInvoker.call_isatty(fd) != 0; } - @ExportMessage + @Override + @TruffleBoundary public Object opendir(Object path) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1326,7 +1374,8 @@ public Object opendir(Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object fdopendir(int fd) throws PosixException { long ptr = posixNativeFunctionInvoker.call_fdopendir(fd); if (ptr == 0) { @@ -1335,7 +1384,8 @@ public Object fdopendir(int fd) throws PosixException { return ptr; } - @ExportMessage + @Override + @TruffleBoundary public void closedir(Object dirStreamObj) throws PosixException { int res = posixNativeFunctionInvoker.call_closedir(((Long) dirStreamObj).longValue()); if (res != 0) { @@ -1343,7 +1393,8 @@ public void closedir(Object dirStreamObj) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object readdir(Object dirStreamObj) throws PosixException { int nameBufBytes = WINDOWS ? DIRENT_NAME_BUF_LENGTH * 2 : DIRENT_NAME_BUF_LENGTH; byte[] name = new byte[nameBufBytes]; @@ -1378,70 +1429,55 @@ public Object readdir(Object dirStreamObj) throws PosixException { return null; } - @ExportMessage + @Override + @TruffleBoundary public void rewinddir(Object dirStreamObj) { - posixNativeFunctionInvoker.call_rewinddir(((Long) dirStreamObj).longValue()); + posixNativeFunctionInvoker.call_rewinddir((Long) dirStreamObj); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public Object dirEntryGetName(Object dirEntryObj) { DirEntry dirEntry = (DirEntry) dirEntryObj; return dirEntry.name; } - @ExportMessage - public static class DirEntryGetPath { - @Specialization(guards = "endsWithSlash(scandirPath)") - static NativePath withSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { - NativePath scandirPathBuffer = (NativePath) scandirPath; - int pathLen = scandirPathBuffer.data.length; - int nameLen = dirEntry.name.data.length; - byte[] buf = new byte[pathLen + nameLen]; - PythonUtils.arraycopy(scandirPathBuffer.data, 0, buf, 0, pathLen); - PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen, nameLen); - return createLike(scandirPathBuffer, buf); - } - - @Specialization(guards = "!endsWithSlash(scandirPath)") - static NativePath withoutSlash(@SuppressWarnings("unused") NativePosixSupport receiver, DirEntry dirEntry, Object scandirPath) { - NativePath scandirPathBuffer = (NativePath) scandirPath; - int pathLen = scandirPathBuffer.data.length; - int nameLen = dirEntry.name.data.length; - int separatorBytes = scandirPathBuffer instanceof WidePath ? 2 : 1; - byte[] buf = new byte[pathLen + separatorBytes + nameLen]; - PythonUtils.arraycopy(scandirPathBuffer.data, 0, buf, 0, pathLen); - buf[pathLen] = (byte) (scandirPathBuffer instanceof WidePath ? '\\' : '/'); - PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen + separatorBytes, nameLen); - return createLike(scandirPathBuffer, buf); - } - - protected static boolean endsWithSlash(Object path) { - NativePath b = (NativePath) path; - byte last = b.data[b.data.length - (b instanceof WidePath ? 2 : 1)]; - return last == '/' || last == '\\'; - } - - private static NativePath createLike(NativePath path, byte[] data) { - return path instanceof WidePath ? new WidePath(data) : new NarrowPath(data); - } + @Override + @TruffleBoundary + public Object dirEntryGetPath(Object dirEntryObj, Object scandirPath) { + DirEntry dirEntry = (DirEntry) dirEntryObj; + NativePath path = (NativePath) scandirPath; + int pathLen = path.data.length; + int nameLen = dirEntry.name.data.length; + boolean wide = path instanceof WidePath; + byte last = path.data[pathLen - (wide ? 2 : 1)]; + boolean hasSlash = last == '/' || last == '\\'; + int separatorBytes = hasSlash ? 0 : wide ? 2 : 1; + byte[] buf = new byte[pathLen + separatorBytes + nameLen]; + PythonUtils.arraycopy(path.data, 0, buf, 0, pathLen); + if (!hasSlash) { + buf[pathLen] = (byte) (wide ? '\\' : '/'); + } + PythonUtils.arraycopy(dirEntry.name.data, 0, buf, pathLen + separatorBytes, nameLen); + return wide ? new WidePath(buf) : new NarrowPath(buf); } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public long dirEntryGetInode(Object dirEntry) { DirEntry entry = (DirEntry) dirEntry; return entry.ino; } - @ExportMessage - @SuppressWarnings("static-method") + @Override + @TruffleBoundary public int dirEntryGetType(Object dirEntryObj) { DirEntry dirEntry = (DirEntry) dirEntryObj; return dirEntry.type; } - @ExportMessage + @Override + @TruffleBoundary public void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { assert PosixConstants.HAVE_UTIMENSAT.value; assert timespec == null || timespec.length == 4; @@ -1460,7 +1496,8 @@ public void utimensat(int dirFd, Object pathname, long[] timespec, boolean follo } } - @ExportMessage + @Override + @TruffleBoundary public void futimens(int fd, long[] timespec) throws PosixException { assert PosixConstants.HAVE_FUTIMENS.value; assert timespec == null || timespec.length == 4; @@ -1475,7 +1512,8 @@ public void futimens(int fd, long[] timespec) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void futimes(int fd, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long timevalPtr = copyTimevalArrayToNativeOrNull(timeval); @@ -1489,7 +1527,8 @@ public void futimes(int fd, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void lutimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long filenamePtr = NULLPTR; @@ -1507,7 +1546,8 @@ public void lutimes(Object filename, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void utimes(Object filename, Timeval[] timeval) throws PosixException { assert timeval == null || timeval.length == 2; long filenamePtr = NULLPTR; @@ -1525,7 +1565,8 @@ public void utimes(Object filename, Timeval[] timeval) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; @@ -1542,7 +1583,8 @@ public void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) } } - @ExportMessage + @Override + @TruffleBoundary public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { long oldPathPtr = NULLPTR; long newPathPtr = NULLPTR; @@ -1559,7 +1601,8 @@ public void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath } } - @ExportMessage + @Override + @TruffleBoundary public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) { long pathPtr = pathToNativeCString(path); int ret; @@ -1569,12 +1612,13 @@ public boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, NativeMemory.free(pathPtr); } if (ret != 0 && LOGGER.isLoggable(Level.FINE)) { - log(Level.FINE, "faccessat return value: %d, errno: %d", ret, getErrno()); + LOGGER.fine(String.format("faccessat return value: %d, errno: %d", ret, getErrno())); } return ret == 0; } - @ExportMessage + @Override + @TruffleBoundary public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1587,7 +1631,8 @@ public void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) t } } - @ExportMessage + @Override + @TruffleBoundary public void fchmod(int fd, int mode) throws PosixException { int ret = posixNativeFunctionInvoker.call_fchmod(fd, mode); if (ret != 0) { @@ -1595,7 +1640,8 @@ public void fchmod(int fd, int mode) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { long pathPtr = pathToNativeCString(path); try { @@ -1608,7 +1654,8 @@ public void fchownat(int dirFd, Object path, long owner, long group, boolean fol } } - @ExportMessage + @Override + @TruffleBoundary public void fchown(int fd, long owner, long group) throws PosixException { int ret = posixNativeFunctionInvoker.call_fchown(fd, owner, group); if (ret != 0) { @@ -1616,7 +1663,8 @@ public void fchown(int fd, long owner, long group) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object readlinkat(int dirFd, Object path) throws PosixException { int bufferBytes = WINDOWS ? PATH_MAX.value * 2 : PATH_MAX.value; byte[] buffer = new byte[bufferBytes]; @@ -1640,7 +1688,8 @@ public Object readlinkat(int dirFd, Object path) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void kill(long pid, int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_kill(pid, signal); if (res == -1) { @@ -1648,7 +1697,8 @@ public void kill(long pid, int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void raise(int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_raise(signal); if (res != 0) { @@ -1656,12 +1706,14 @@ public void raise(int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int alarm(int seconds) { return posixNativeFunctionInvoker.call_alarm(seconds); } - @ExportMessage + @Override + @TruffleBoundary public Timeval[] getitimer(int which) throws PosixException { long nativeCurrentValue = NativeMemory.mallocLongArray(4); try { @@ -1675,7 +1727,8 @@ public Timeval[] getitimer(int which) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { long nativeNewValue = NULLPTR; long nativeOldValue = NULLPTR; @@ -1693,7 +1746,8 @@ public Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws Po } } - @ExportMessage + @Override + @TruffleBoundary public void signalSelf(int signal) throws PosixException { if (!ImageInfo.inImageRuntimeCode()) { throw new UnsupportedPosixFeatureException("self-signals are only supported in native standalone"); @@ -1704,7 +1758,8 @@ public void signalSelf(int signal) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void killpg(long pgid, int signal) throws PosixException { int res = posixNativeFunctionInvoker.call_killpg(pgid, signal); if (res == -1) { @@ -1712,9 +1767,9 @@ public void killpg(long pgid, int signal) throws PosixException { } } - @ExportMessage - public long[] waitpid(long pid, int options, - @Bind Node node) throws PosixException { + @Override + @TruffleBoundary + public long[] waitpid(Node node, long pid, int options) throws PosixException { boolean hasNohang = (options & WNOHANG.getValueIfDefined()) != 0; int subOptions = options | WNOHANG.getValueIfDefined(); long nativeStatus = NativeMemory.callocIntArray(1); @@ -1735,72 +1790,86 @@ public long[] waitpid(long pid, int options, } } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wcoredump(int status) { return posixNativeFunctionInvoker.call_wcoredump(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifcontinued(int status) { return posixNativeFunctionInvoker.call_wifcontinued(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifstopped(int status) { return posixNativeFunctionInvoker.call_wifstopped(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifsignaled(int status) { return posixNativeFunctionInvoker.call_wifsignaled(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public boolean wifexited(int status) { return posixNativeFunctionInvoker.call_wifexited(status) != 0; } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wexitstatus(int status) { return posixNativeFunctionInvoker.call_wexitstatus(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wtermsig(int status) { return posixNativeFunctionInvoker.call_wtermsig(status); } - @ExportMessage + @Override + @TruffleBoundary(allowInlining = true) public int wstopsig(int status) { return posixNativeFunctionInvoker.call_wstopsig(status); } - @ExportMessage + @Override + @TruffleBoundary public long getuid() { return posixNativeFunctionInvoker.call_getuid(); } - @ExportMessage + @Override + @TruffleBoundary public long geteuid() { return posixNativeFunctionInvoker.call_geteuid(); } - @ExportMessage + @Override + @TruffleBoundary public long getgid() { return posixNativeFunctionInvoker.call_getgid(); } - @ExportMessage + @Override + @TruffleBoundary public long getegid() { return posixNativeFunctionInvoker.call_getegid(); } - @ExportMessage + @Override + @TruffleBoundary public long getppid() { return posixNativeFunctionInvoker.call_getppid(); } - @ExportMessage + @Override + @TruffleBoundary public void setpgid(long pid, long pgid) throws PosixException { int res = posixNativeFunctionInvoker.call_setpgid(pid, pgid); if (res < 0) { @@ -1808,7 +1877,8 @@ public void setpgid(long pid, long pgid) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public long getpgid(long pid) throws PosixException { long res = posixNativeFunctionInvoker.call_getpgid(pid); if (res < 0) { @@ -1817,12 +1887,14 @@ public long getpgid(long pid) throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long getpgrp() { return posixNativeFunctionInvoker.call_getpgrp(); } - @ExportMessage + @Override + @TruffleBoundary public long getsid(long pid) throws PosixException { long res = posixNativeFunctionInvoker.call_getsid(pid); if (res < 0) { @@ -1831,7 +1903,8 @@ public long getsid(long pid) throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long setsid() throws PosixException { long res = posixNativeFunctionInvoker.call_setsid(); if (res < 0) { @@ -1840,7 +1913,8 @@ public long setsid() throws PosixException { return res; } - @ExportMessage + @Override + @TruffleBoundary public long[] getgroups() throws PosixException { // The first call gets us the number of groups, so we can allocate the output array int res = posixNativeFunctionInvoker.call_getgroups(0, NULLPTR); @@ -1864,7 +1938,8 @@ public long[] getgroups() throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public RusageResult getrusage(int who) throws PosixException { long nativeResult = NativeMemory.mallocLongArray(16); try { @@ -1894,7 +1969,8 @@ public RusageResult getrusage(int who) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public OpenPtyResult openpty() throws PosixException { long nativeOutvars = NativeMemory.mallocIntArray(2); try { @@ -1910,21 +1986,25 @@ public OpenPtyResult openpty() throws PosixException { } } - @ExportMessage - public TruffleString ctermid( - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) { + @Override + @TruffleBoundary + public Buffer ctermid() { long nativeBuf = NativeMemory.mallocByteArray(L_ctermid.value); try { posixNativeFunctionInvoker.call_ctermid(nativeBuf); - // TODO PyUnicode_DecodeFSDefault - return zeroTerminatedUtf8ToTruffleStringNode.execute(inliningTarget, nativeBuf); + int length = 0; + while (length < L_ctermid.value && NativeMemory.readByte(nativeBuf + length) != 0) { + length++; + } + byte[] result = NativeMemory.readByteArrayElements(nativeBuf, 0, length); + return Buffer.wrap(result); } finally { NativeMemory.free(nativeBuf); } } - @ExportMessage + @Override + @TruffleBoundary public void setenv(Object name, Object value, boolean overwrite) throws PosixException { long namePtr = NULLPTR; long valuePtr = NULLPTR; @@ -1941,7 +2021,8 @@ public void setenv(Object name, Object value, boolean overwrite) throws PosixExc } } - @ExportMessage + @Override + @TruffleBoundary public void unsetenv(Object name) throws PosixException { long namePtr = opaqueStringToNative(name); try { @@ -1954,7 +2035,8 @@ public void unsetenv(Object name) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { @@ -2068,7 +2150,8 @@ public int forkExec(Object[] executables, Object[] args, Object cwd, Object[] en } } - @ExportMessage + @Override + @TruffleBoundary public void execv(Object pathname, Object[] args) throws PosixException { if (WINDOWS) { @@ -2129,7 +2212,8 @@ public void execv(Object pathname, Object[] args) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int system(Object command) { long commandPtr = opaqueStringToNative(command); try { @@ -2141,8 +2225,8 @@ public int system(Object command) { private static long addLengthsOfCStrings(long prevLen, Object[] src) throws OverflowException { long len = prevLen; - for (Object o : src) { - len = PythonUtils.addExact(len, ((Buffer) o).length); + for (int i = 0; i < src.length; i++) { + len = PythonUtils.addExact(len, ((Buffer) src[i]).length); } return PythonUtils.addExact(len, src.length); // add space for terminating '\0' } @@ -2178,18 +2262,16 @@ public MMapHandle(long pointer, long length) { } } - @ExportMessage - public Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) throws PosixException { + @Override + @TruffleBoundary + public Object mmap(Node inliningTarget, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { long tagnamePtr = NULLPTR; try { if (tagname instanceof TruffleString tagnameString) { tagnamePtr = WINDOWS - ? stringToNativeUTF16CString(tagnameString, switchEncodingNode, copyToByteArrayNode) - : stringToNativeUTF8CString(inliningTarget, tagnameString, switchEncodingNode, isValidNode, copyToByteArrayNode); + ? stringToNativeUTF16CString(tagnameString, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.CopyToByteArrayNode.getUncached()) + : stringToNativeUTF8CString(inliningTarget, tagnameString, TruffleString.SwitchEncodingNode.getUncached(), TruffleString.IsValidNode.getUncached(), + TruffleString.CopyToByteArrayNode.getUncached()); } long address = posixNativeFunctionInvoker.call_mmap(length, prot, flags, fd, offset, tagnamePtr); if (address == 0) { @@ -2201,7 +2283,8 @@ public Object mmap(long length, int prot, int flags, int fd, long offset, Object } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public byte mmapReadByte(Object mmap, long index) { MMapHandle handle = (MMapHandle) mmap; @@ -2212,7 +2295,8 @@ public byte mmapReadByte(Object mmap, long index) { return UNSAFE.getByte(handle.pointer + index); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void mmapWriteByte(Object mmap, long index, byte value) { MMapHandle handle = (MMapHandle) mmap; @@ -2220,7 +2304,8 @@ public void mmapWriteByte(Object mmap, long index, byte value) { UNSAFE.putByte(handle.pointer + index, value); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) { MMapHandle handle = (MMapHandle) mmap; @@ -2229,7 +2314,8 @@ public int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) { return length; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) { MMapHandle handle = (MMapHandle) mmap; @@ -2237,14 +2323,16 @@ public void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) { UNSAFE.copyMemory(bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, handle.pointer + index, length); } - @ExportMessage + @Override + @TruffleBoundary public void mmapFlush(Object mmap, long offset, long length) { MMapHandle handle = (MMapHandle) mmap; checkIndexAndLen(handle, offset, length); posixNativeFunctionInvoker.call_msync(handle.pointer, offset, length); } - @ExportMessage + @Override + @TruffleBoundary public void mmapUnmap(Object mmap, long length) throws PosixException { MMapHandle handle = (MMapHandle) mmap; if (length != handle.length) { @@ -2257,7 +2345,8 @@ public void mmapUnmap(Object mmap, long length) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public long mmapGetPointer(Object mmap) { MMapHandle handle = (MMapHandle) mmap; @@ -2275,7 +2364,8 @@ private static void checkIndexAndLen(MMapHandle handle, long index, long length) } } - @ExportMessage + @Override + @TruffleBoundary public int socket(int domain, int type, int protocol) throws PosixException { int result = posixNativeFunctionInvoker.call_socket(domain, type, protocol); if (result == -1) { @@ -2284,7 +2374,8 @@ public int socket(int domain, int type, int protocol) throws PosixException { return result; } - @ExportMessage + @Override + @TruffleBoundary public AcceptResult accept(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; @@ -2304,7 +2395,8 @@ public AcceptResult accept(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void bind(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; int addrLen = addr.getLen(); @@ -2320,7 +2412,8 @@ public void bind(int sockfd, UniversalSockAddr usa) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void connect(int sockfd, UniversalSockAddr usa) throws PosixException { UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; int addrLen = addr.getLen(); @@ -2336,7 +2429,8 @@ public void connect(int sockfd, UniversalSockAddr usa) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public void listen(int sockfd, int backlog) throws PosixException { int result = posixNativeFunctionInvoker.call_listen(sockfd, backlog); if (result == -1) { @@ -2344,7 +2438,8 @@ public void listen(int sockfd, int backlog) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public UniversalSockAddr getpeername(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; @@ -2364,7 +2459,8 @@ public UniversalSockAddr getpeername(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public UniversalSockAddr getsockname(int sockfd) throws PosixException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); long nativeAddr = NULLPTR; @@ -2384,7 +2480,8 @@ public UniversalSockAddr getsockname(int sockfd) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); @@ -2400,7 +2497,8 @@ public int send(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override + @TruffleBoundary public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr usa) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl destAddr = (UniversalSockAddrImpl) usa; @@ -2423,7 +2521,8 @@ public int sendto(int sockfd, byte[] buf, int offset, int len, int flags, Univer } } - @ExportMessage + @Override + @TruffleBoundary public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); long nativeBuffer = NativeMemory.mallocByteArrayOrNull(len); @@ -2439,7 +2538,8 @@ public int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws P } } - @ExportMessage + @Override + @TruffleBoundary public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkBounds(buf, offset, len); UniversalSockAddrImpl srcAddr = new UniversalSockAddrImpl(this); @@ -2464,7 +2564,8 @@ public RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int } } - @ExportMessage + @Override + @TruffleBoundary public void shutdown(int sockfd, int how) throws PosixException { int res = posixNativeFunctionInvoker.call_shutdown(sockfd, how); if (res != 0) { @@ -2472,7 +2573,8 @@ public void shutdown(int sockfd, int how) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; long nativeOptval = NULLPTR; @@ -2499,7 +2601,8 @@ public int getsockopt(int sockfd, int level, int optname, byte[] optval, int opt } } - @ExportMessage + @Override + @TruffleBoundary public void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { assert optlen >= 0 && optval.length >= optlen; long nativeOptval = NULLPTR; @@ -2514,7 +2617,8 @@ public void setsockopt(int sockfd, int level, int optname, byte[] optval, int op } } - @ExportMessage + @Override + @TruffleBoundary public int inet_addr(Object src) { long srcPtr = bufferToNativeCString((Buffer) src); try { @@ -2524,7 +2628,8 @@ public int inet_addr(Object src) { } } - @ExportMessage + @Override + @TruffleBoundary public int inet_aton(Object src) throws InvalidAddressException { long srcPtr = bufferToNativeCString((Buffer) src); try { @@ -2538,7 +2643,8 @@ public int inet_aton(Object src) throws InvalidAddressException { } } - @ExportMessage + @Override + @TruffleBoundary public Object inet_ntoa(int src) { Buffer buf = Buffer.allocate(INET_ADDRSTRLEN.value); long nativeBuf = NativeMemory.mallocByteArray(INET_ADDRSTRLEN.value); @@ -2553,7 +2659,8 @@ public Object inet_ntoa(int src) { } } - @ExportMessage + @Override + @TruffleBoundary public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { byte[] buf = new byte[family == AF_INET.value ? 4 : 16]; long srcPtr = NULLPTR; @@ -2579,7 +2686,8 @@ public byte[] inet_pton(int family, Object src) throws PosixException, InvalidAd } } - @ExportMessage + @Override + @TruffleBoundary public Object inet_ntop(int family, byte[] src) throws PosixException { if ((family == AF_INET.value && src.length < 4) || (family == AF_INET6.value && src.length < 16)) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -2603,7 +2711,8 @@ public Object inet_ntop(int family, byte[] src) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public Object gethostname() throws PosixException { int maxLen = (HOST_NAME_MAX.defined ? HOST_NAME_MAX.getValueIfDefined() : _POSIX_HOST_NAME_MAX.value) + 1; if (maxLen <= 1) { @@ -2626,10 +2735,9 @@ public Object gethostname() throws PosixException { } } - @ExportMessage - public Object[] getnameinfo(UniversalSockAddr usa, int flags, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { + @Override + @TruffleBoundary + public Object[] getnameinfo(UniversalSockAddr usa, int flags) throws GetAddrInfoException { Buffer host = Buffer.allocate(NI_MAXHOST.value); Buffer serv = Buffer.allocate(NI_MAXSERV.value); UniversalSockAddrImpl addr = (UniversalSockAddrImpl) usa; @@ -2642,7 +2750,7 @@ public Object[] getnameinfo(UniversalSockAddr usa, int flags, nativeServ = NativeMemory.mallocByteArray(NI_MAXSERV.value); int res = posixNativeFunctionInvoker.call_getnameinfo(nativeAddr, addr.getLen(), nativeHost, NI_MAXHOST.value, nativeServ, NI_MAXSERV.value, flags); if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + throw new GetAddrInfoException(res, gai_strerror(null, res, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached())); } NativeMemory.readByteArrayElements(nativeHost, 0, host.data, 0, host.data.length); NativeMemory.readByteArrayElements(nativeServ, 0, serv.data, 0, serv.data.length); @@ -2657,10 +2765,9 @@ public Object[] getnameinfo(UniversalSockAddr usa, int flags, } } - @ExportMessage - public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @Bind Node inliningTarget, - @Shared("cString") @Cached NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode zeroTerminatedUtf8ToTruffleStringNode) throws GetAddrInfoException { + @Override + @TruffleBoundary + public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws GetAddrInfoException { long nodePtr = NULLPTR; long servicePtr = NULLPTR; long nativePtr = NULLPTR; @@ -2670,7 +2777,7 @@ public AddrInfoCursor getaddrinfo(Object node, Object service, int family, int s nativePtr = NativeMemory.mallocLongArray(1); int res = posixNativeFunctionInvoker.call_getaddrinfo(nodePtr, servicePtr, family, sockType, protocol, flags, nativePtr); if (res != 0) { - throw new GetAddrInfoException(res, gai_strerror(inliningTarget, res, zeroTerminatedUtf8ToTruffleStringNode)); + throw new GetAddrInfoException(res, gai_strerror(null, res, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached())); } long head = NativeMemory.readLong(nativePtr); assert head != 0; // getaddrinfo should return at least one result @@ -2794,7 +2901,6 @@ long getNextPtr() { } } - @ExportLibrary(AddrInfoCursorLibrary.class) protected static class AddrInfoCursorImpl implements AddrInfoCursor { private final NativePosixSupport nativePosixSupport; @@ -2808,15 +2914,17 @@ protected static class AddrInfoCursorImpl implements AddrInfoCursor { info.update(head, nativePosixSupport); } - @ExportMessage - void release() { + @Override + @TruffleBoundary + public void release() { checkReleased(); nativePosixSupport.posixNativeFunctionInvoker.call_freeaddrinfo(head); head = 0; } - @ExportMessage - boolean next() { + @Override + @TruffleBoundary + public boolean next() { checkReleased(); long nextPtr = info.getNextPtr(); if (nextPtr == 0) { @@ -2826,32 +2934,37 @@ boolean next() { return true; } - @ExportMessage - int getFlags() { + @Override + @TruffleBoundary + public int getFlags() { checkReleased(); return info.getFlags(); } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { checkReleased(); return info.getFamily(); } - @ExportMessage - int getSockType() { + @Override + @TruffleBoundary + public int getSockType() { checkReleased(); return info.getSockType(); } - @ExportMessage - int getProtocol() { + @Override + @TruffleBoundary + public int getProtocol() { checkReleased(); return info.getProtocol(); } - @ExportMessage - Object getCanonName() { + @Override + @TruffleBoundary + public Object getCanonName() { checkReleased(); long namePtr = info.getCanonNamePtr(); if (namePtr == 0) { @@ -2863,8 +2976,9 @@ Object getCanonName() { return Buffer.wrap(buf); } - @ExportMessage - UniversalSockAddr getSockAddr() { + @Override + @TruffleBoundary + public UniversalSockAddr getSockAddr() { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(nativePosixSupport); PythonUtils.arraycopy(info.socketAddress, 0, addr.data, 0, info.getAddrLen()); addr.setFamily(info.getAddrFamily()); @@ -2879,8 +2993,9 @@ private void checkReleased() { } } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_INET.value); ARRAY_ACCESSOR_BE.putShort(addr.data, getConstant(OFFSETOF_STRUCT_SOCKADDR_IN_SIN_PORT), (short) src.getPort()); @@ -2889,8 +3004,9 @@ UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { return addr; } - @ExportMessage - UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_INET6.value); ARRAY_ACCESSOR_BE.putShort(addr.data, getConstant(OFFSETOF_STRUCT_SOCKADDR_IN6_SIN6_PORT), (short) src.getPort()); @@ -2902,8 +3018,9 @@ UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { return addr; } - @ExportMessage - UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUnixSocketPathException { UniversalSockAddrImpl addr = new UniversalSockAddrImpl(this); addr.setFamily(AF_UNIX.value); byte[] path = src.getPath(); @@ -2916,7 +3033,6 @@ UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws InvalidUn return addr; } - @ExportLibrary(UniversalSockAddrLibrary.class) protected static class UniversalSockAddrImpl implements UniversalSockAddr { private final NativePosixSupport nativePosixSupport; @@ -2928,8 +3044,9 @@ protected static class UniversalSockAddrImpl implements UniversalSockAddr { this.data = new byte[(int) getConstant(SIZEOF_STRUCT_SOCKADDR_STORAGE)]; } - @ExportMessage - int getFamily() { + @Override + @TruffleBoundary + public int getFamily() { int offset = (int) getConstant(OFFSETOF_STRUCT_SOCKADDR_SA_FAMILY); int size = (int) getConstant(SIZEOF_STRUCT_SOCKADDR_SA_FAMILY); if (getLen() >= offset + size) { @@ -2961,8 +3078,9 @@ void setFamily(int family) { } } - @ExportMessage - Inet4SockAddr asInet4SockAddr() { + @Override + @TruffleBoundary + public Inet4SockAddr asInet4SockAddr() { if (getFamily() != AF_INET.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_INET socket address can be converted to Inet4SockAddr"); } @@ -2974,8 +3092,9 @@ Inet4SockAddr asInet4SockAddr() { return new Inet4SockAddr(port, address); } - @ExportMessage - Inet6SockAddr asInet6SockAddr() { + @Override + @TruffleBoundary + public Inet6SockAddr asInet6SockAddr() { if (getFamily() != AF_INET6.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_INET6 socket address can be converted to Inet6SockAddr"); } @@ -2990,8 +3109,9 @@ Inet6SockAddr asInet6SockAddr() { return new Inet6SockAddr(port, address, flowInfo, scopeId); } - @ExportMessage - UnixSockAddr asUnixSockAddr() { + @Override + @TruffleBoundary + public UnixSockAddr asUnixSockAddr() { if (getFamily() != AF_UNIX.value) { throw CompilerDirectives.shouldNotReachHere("Only AF_UNIX socket address can be converted to UnixSockAddr"); } @@ -3024,8 +3144,9 @@ void setLen(int len) { } - @ExportMessage - long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { + @Override + @TruffleBoundary + public long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { long ptr = posixNativeFunctionInvoker.call_sem_open(namePtr, openFlags, mode, value); @@ -3038,16 +3159,18 @@ long semOpen(Object name, int openFlags, int mode, int value) throws PosixExcept } } - @ExportMessage - void semClose(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semClose(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_close(handle); if (res < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - void semUnlink(Object name) throws PosixException { + @Override + @TruffleBoundary + public void semUnlink(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int res = posixNativeFunctionInvoker.call_sem_unlink(namePtr); @@ -3059,8 +3182,9 @@ void semUnlink(Object name) throws PosixException { } } - @ExportMessage - int shmOpen(Object name, int openFlags, int mode) throws PosixException { + @Override + @TruffleBoundary + public int shmOpen(Object name, int openFlags, int mode) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int fd = posixNativeFunctionInvoker.call_shm_open(namePtr, openFlags, mode); @@ -3073,8 +3197,9 @@ int shmOpen(Object name, int openFlags, int mode) throws PosixException { } } - @ExportMessage - void shmUnlink(Object name) throws PosixException { + @Override + @TruffleBoundary + public void shmUnlink(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { int res = posixNativeFunctionInvoker.call_shm_unlink(namePtr); @@ -3088,8 +3213,9 @@ void shmUnlink(Object name) throws PosixException { private static final UnsupportedPosixFeatureException NO_SEM_GETVALUE_EXCEPTION = new UnsupportedPosixFeatureException("sem_getvalue is not available on the current platform"); - @ExportMessage - int semGetValue(long handle) throws PosixException { + @Override + @TruffleBoundary + public int semGetValue(long handle) throws PosixException { /* * This works on Linux and is emulated with Windows semaphore APIs as on CPython. It * doesn't work on Darwin. It might work on some other Unix-likes, but it's hard to check, @@ -3110,24 +3236,27 @@ int semGetValue(long handle) throws PosixException { } } - @ExportMessage - void semPost(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semPost(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_post(handle); if (res < 0) { throw getSemPostErrnoAndThrowPosixException(); } } - @ExportMessage - void semWait(long handle) throws PosixException { + @Override + @TruffleBoundary + public void semWait(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_wait(handle); if (res < 0) { throw getErrnoAndThrowPosixException(); } } - @ExportMessage - boolean semTryWait(long handle) throws PosixException { + @Override + @TruffleBoundary + public boolean semTryWait(long handle) throws PosixException { int res = posixNativeFunctionInvoker.call_sem_trywait(handle); if (res < 0) { int errno = getErrno(); @@ -3139,10 +3268,9 @@ boolean semTryWait(long handle) throws PosixException { return true; } - @ExportMessage - boolean semTimedWait(long handle, long deadlineNs, - @Bind Node node, - @CachedLibrary("this") PosixSupportLibrary thisLib) throws PosixException { + @Override + @TruffleBoundary + public boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { if (PythonLanguage.getPythonOS() == PythonOS.PLATFORM_LINUX) { int res = posixNativeFunctionInvoker.call_sem_timedwait(handle, deadlineNs); if (res < 0) { @@ -3156,7 +3284,7 @@ boolean semTimedWait(long handle, long deadlineNs, } else { long deadlineMs = deadlineNs / 1_000_000; while (true) { - if (thisLib.semTryWait(this, handle)) { + if (semTryWait(handle)) { return true; } long currentMs = System.currentTimeMillis(); @@ -3164,49 +3292,47 @@ boolean semTimedWait(long handle, long deadlineNs, return false; } long delayMs = Math.min(deadlineMs - currentMs, 20); - TruffleSafepoint.setBlockedThreadInterruptible(node, Thread::sleep, delayMs); + TruffleSafepoint.setBlockedThreadInterruptible(location, Thread::sleep, delayMs); } } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwuid(long uid, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { - return getpw(uid, NULLPTR, fromByteArrayNode, switchEncodingFromUtf8Node); + public NativePwdResult getpwuid(long uid) throws PosixException { + return getpw(uid, NULLPTR); } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult getpwnam(Object name, - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + public NativePwdResult getpwnam(Object name) throws PosixException { long namePtr = bufferToNativeCString((Buffer) name); try { - return getpw(-1, namePtr, fromByteArrayNode, switchEncodingFromUtf8Node); + return getpw(-1, namePtr); } finally { NativeMemory.free(namePtr); } } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") public boolean hasGetpwentries() { return true; } - @ExportMessage + @Override + @TruffleBoundary @SuppressWarnings("static-method") - public PwdResult[] getpwentries( - @Shared("tsFromBytes") @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Shared("fromUtf8") @Cached TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + public NativePwdResult[] getpwentries() throws PosixException { // Note: this is not thread safe, so potentially problematic while running multiple contexts // within one VM int sysConfMax = getSysConfPwdSizeMax(); int initialBufferSize = sysConfMax == -1 ? 1024 : sysConfMax; - ArrayList result = new ArrayList<>(); + ArrayList result = new ArrayList<>(); posixNativeFunctionInvoker.call_setpwent(); long nativeBufferSize = NULLPTR; long nativeOutput = NULLPTR; @@ -3238,7 +3364,7 @@ public PwdResult[] getpwentries( NativeMemory.readByteArrayElements(nativeBuffer, 0, buffer, 0, buffer.length); long[] output = new long[PWD_OUTPUT_LEN]; NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); - result.add(createPwdResult(buffer, output, fromByteArrayNode, switchEncodingFromUtf8Node)); + result.add(createPwdResult(buffer, output)); } } finally { posixNativeFunctionInvoker.call_endpwent(); @@ -3246,16 +3372,10 @@ public PwdResult[] getpwentries( NativeMemory.free(nativeOutput); NativeMemory.free(nativeBufferSize); } - return toPwdResultArray(result); + return result.toArray(new NativePwdResult[0]); } - @TruffleBoundary - private static PwdResult[] toPwdResultArray(ArrayList result) { - return result.toArray(new PwdResult[0]); - } - - private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + private NativePwdResult getpw(long uid, long namePtr) throws PosixException { int sysConfMax = getSysConfPwdSizeMax(); int bufferSize = sysConfMax == -1 ? 1024 : sysConfMax; while (bufferSize < PWD_BUFFER_MAX_SIZE) { @@ -3275,13 +3395,12 @@ private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode NativeMemory.readByteArrayElements(nativeData, 0, data, 0, data.length); long[] output = new long[PWD_OUTPUT_LEN]; NativeMemory.readLongArrayElements(nativeOutput, 0, output, 0, output.length); - return createPwdResult(data, output, fromByteArrayNode, switchEncodingFromUtf8Node); + return createPwdResult(data, output); } - if (result != OSErrorEnum.ERANGE.getNumber() || sysConfMax != -1) { - // no point in trying larger buffer if we got different error or the OS already - // told - // us that sysConfMax should be enough... - throw newPosixException(result); + if (result != OSErrorEnum.ERANGE.getNumber()) { + // CPython treats failed lookups as missing entries, except for ERANGE, + // which requires retrying with a larger buffer even if sysconf gave a size. + return null; } } finally { NativeMemory.free(nativeOutput); @@ -3292,16 +3411,16 @@ private PwdResult getpw(long uid, long namePtr, TruffleString.FromByteArrayNode throw outOfMemoryPosixError(); } - private static PwdResult createPwdResult(byte[] data, long[] output, TruffleString.FromByteArrayNode fromByteArrayNode, TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) - throws PosixException { - return new PwdResult( - extractZeroTerminatedString(data, output[0], fromByteArrayNode, switchEncodingFromUtf8Node), + private static NativePwdResult createPwdResult(byte[] data, long[] output) throws PosixException { + return new NativePwdResult( + Buffer.wrap(extractZeroTerminatedBytes(data, output[0])), output[1], output[2], - extractZeroTerminatedString(data, output[3], fromByteArrayNode, switchEncodingFromUtf8Node), - extractZeroTerminatedString(data, output[4], fromByteArrayNode, switchEncodingFromUtf8Node)); + Buffer.wrap(extractZeroTerminatedBytes(data, output[3])), + Buffer.wrap(extractZeroTerminatedBytes(data, output[4]))); } - @ExportMessage + @Override + @TruffleBoundary public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { long nativeArg = NULLPTR; try { @@ -3322,7 +3441,8 @@ public int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { } } - @ExportMessage + @Override + @TruffleBoundary public int ioctlInt(int fd, long request, int arg) throws PosixException { int res = posixNativeFunctionInvoker.call_ioctl_int(fd, request, arg); if (res < 0) { @@ -3331,8 +3451,7 @@ public int ioctlInt(int fd, long request, int arg) throws PosixException { return res; } - private static TruffleString extractZeroTerminatedString(byte[] buffer, long longOffset, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingFromUtf8Node) throws PosixException { + private static byte[] extractZeroTerminatedBytes(byte[] buffer, long longOffset) throws PosixException { if (longOffset < 0 || longOffset >= buffer.length) { throw outOfMemoryPosixError(); } @@ -3342,7 +3461,7 @@ private static TruffleString extractZeroTerminatedString(byte[] buffer, long lon throw CompilerDirectives.shouldNotReachHere("Could not find the end of the string"); } // TODO PyUnicode_DecodeFSDefault - return createString(buffer, offset, end - offset, true, fromByteArrayNode, switchEncodingFromUtf8Node); + return PythonUtils.arrayCopyOfRange(buffer, offset, end); } private static PosixException outOfMemoryPosixError() throws PosixException { @@ -3363,167 +3482,42 @@ private int getSysConfPwdSizeMax() throws PosixException { } // ------------------ - // Path conversions - - @ExportMessage - @SuppressWarnings("static-method") - public Object createPathFromString(TruffleString path, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode, - @Exclusive @Cached PyUnicodeEncodeFSDefaultNode encodeFSDefaultNode) { - if (WINDOWS) { - TruffleString utf16 = switchEncodingNode.execute(path, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); - } - return checkNarrowPath(encodeFSDefaultNode.execute(null, inliningTarget, path)); - } - - @ExportMessage - @SuppressWarnings("static-method") - public Object createPathFromBytes(byte[] path, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - if (WINDOWS) { - TruffleString utf8 = fromByteArrayNode.execute(path, UTF_8, true); - TruffleString utf16 = switchEncodingNode.execute(utf8, UTF_16LE, windowsPathDecodeErrorHandler(inliningTarget, path)); - return checkWidePath(copyToByteArrayNode.execute(utf16, UTF_16LE)); - } - return checkNarrowPath(path); - } - - @ExportMessage - @SuppressWarnings("static-method") - public TruffleString getPathAsString(Object path, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { - NativePath result = (NativePath) path; - TruffleString encoded = fromByteArrayNode.execute(result.data, 0, result.data.length, result.encoding(), true); - if (result instanceof WidePath) { - return switchEncodingNode.execute(encoded, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - } - TruffleString utf8 = encoded; - if (isValidNode.execute(utf8, UTF_8)) { - return switchEncodingNode.execute(utf8, TS_ENCODING); - } - TranscodingErrorHandler errorHandler = PythonLanguage.getPythonOS() == PythonOS.PLATFORM_WIN32 - ? TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8 - : PyUnicodeFSDecoderNode.SURROGATE_ESCAPE_FROM_UTF8_TRANSCODING_ERROR_HANDLER; - return switchEncodingNode.execute(utf8, TS_ENCODING, errorHandler); - } - - @ExportMessage - @SuppressWarnings("static-method") - public Buffer getPathAsBytes(Object path) { - NativePath nativePath = (NativePath) path; - if (nativePath instanceof NarrowPath) { - return Buffer.wrap(nativePath.data); - } - TruffleString utf16 = TruffleString.fromByteArrayUncached(nativePath.data, UTF_16LE); - TruffleString utf8 = utf16.switchEncodingUncached(UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - InternalByteArray bytes = utf8.getInternalByteArrayUncached(UTF_8); - return Buffer.wrap(PythonUtils.arrayCopyOfRange(bytes.getArray(), bytes.getOffset(), bytes.getEnd())); - } - - private static TranscodingErrorHandler windowsPathDecodeErrorHandler(Node inliningTarget, byte[] input) { - return (AbstractTruffleString sourceString, int byteIndex, int estimatedByteLength, TruffleString.Encoding sourceEncoding, - TruffleString.Encoding targetEncoding) -> { - if (byteIndex + 2 < input.length && (input[byteIndex] & 0xff) == 0xed && - (input[byteIndex + 1] & 0xe0) == 0xa0 && (input[byteIndex + 2] & 0xc0) == 0x80) { - int codePoint = ((input[byteIndex] & 0x0f) << 12) | ((input[byteIndex + 1] & 0x3f) << 6) | (input[byteIndex + 2] & 0x3f); - return new TranscodingErrorHandler.ReplacementString(TruffleString.fromCodePointUncached(codePoint, UTF_16LE, true), 3); - } - Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeDecodeError, - PythonUtils.toTruffleStringUncached("utf-8"), PFactory.createBytes(PythonLanguage.get(inliningTarget), input), - byteIndex, Math.min(input.length, byteIndex + Math.max(1, estimatedByteLength)), - PythonUtils.toTruffleStringUncached("invalid UTF-8 path")); - throw PRaiseNode.raiseExceptionObjectStatic(inliningTarget, exception); - }; - } + // Raw representations used by PosixSupportNodes. These methods deliberately do not create or + // decode TruffleStrings. - @ExportMessage - public Object createCStringFromString(TruffleString string, - @Bind Node inliningTarget, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.IsValidNode isValidNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - return checkCString(getUTF8StringBytes(inliningTarget, string, switchEncodingNode, isValidNode, copyToByteArrayNode)); + @TruffleBoundary + public Object createRawPath(byte[] data, boolean wide) { + return wide ? checkWidePath(data) : checkNarrowPath(data); } - @ExportMessage + @Override + @TruffleBoundary public Object createCStringFromBytes(byte[] bytes) { return checkCString(bytes); } - @ExportMessage - public Object createWideStringFromString(TruffleString string, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode, - @Exclusive @Cached TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - TruffleString utf16 = switchEncodingNode.execute(string, UTF_16LE, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - byte[] bytes = copyToByteArrayNode.execute(utf16, UTF_16LE); - return checkWideString(bytes); + public Object createRawWideString(byte[] data) { + return checkWideString(data); } - @ExportMessage - public TruffleString getCStringAsString(Object string, - @Exclusive @Cached TruffleString.FromByteArrayNode fromByteArrayNode, - @Exclusive @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { - if (string instanceof WideString wideString) { - TruffleString utf16 = fromByteArrayNode.execute(wideString.data, UTF_16LE, true); - return switchEncodingNode.execute(utf16, TS_ENCODING, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - } - Buffer buffer = (Buffer) string; - return createString(buffer.data, 0, (int) buffer.length, true, fromByteArrayNode, switchEncodingNode); + public byte[] getRawPathData(Object path) { + return ((NativePath) path).data; } - @ExportMessage - public Buffer getCStringAsBytes(Object string) { - if (string instanceof WideString wideString) { - TruffleString utf16 = TruffleString.fromByteArrayUncached(wideString.data, UTF_16LE); - TruffleString utf8 = utf16.switchEncodingUncached(UTF_8, TranscodingErrorHandler.DEFAULT_KEEP_SURROGATES_IN_UTF8); - InternalByteArray bytes = utf8.getInternalByteArrayUncached(UTF_8); - return Buffer.wrap(PythonUtils.arrayCopyOfRange(bytes.getArray(), bytes.getOffset(), bytes.getEnd())); - } - return (Buffer) string; + public boolean isWidePath(Object path) { + return ((NativePath) path) instanceof WidePath; } - private static TruffleString createString(byte[] src, int offset, int length, boolean copy, TruffleString.FromByteArrayNode fromByteArrayNode, - TruffleString.SwitchEncodingNode switchEncodingNode) { - TruffleString utf8 = fromByteArrayNode.execute(src, offset, length, UTF_8, copy); - return switchEncodingNode.execute(utf8, TS_ENCODING); + public byte[] getRawStringData(Object string) { + return string instanceof WideString ? ((WideString) string).data : ((Buffer) string).data; } - private static byte[] getUTF8StringBytes(Node node, TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.IsValidNode isValidNode, - TruffleString.CopyToByteArrayNode copyToByteArrayNode) { - if (!isValidNode.execute(str, TS_ENCODING)) { - throw raiseSurrogatesEncodeError(node, str); - } - TruffleString utf8 = switchEncodingNode.execute(str, UTF_8); - byte[] bytes = new byte[utf8.byteLength(UTF_8)]; - copyToByteArrayNode.execute(utf8, 0, bytes, 0, bytes.length, UTF_8); - return bytes; + public boolean isWideString(Object string) { + return string instanceof WideString; } - @TruffleBoundary - private static PException raiseSurrogatesEncodeError(Node node, TruffleString str) { - int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(str, 0, str.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); - int start = byteIndex < 0 ? 0 : byteIndex / 4; - int length = str.codePointLengthUncached(TS_ENCODING); - int end = Math.min(start + 1, length); - while (end < length) { - int codePoint = str.codePointAtIndexUncached(end, TS_ENCODING); - if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { - break; - } - end++; - } - Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeEncodeError, - PythonUtils.toTruffleStringUncached("utf-8"), str, start, end, - PythonUtils.toTruffleStringUncached("surrogates not allowed")); - return PRaiseNode.raiseExceptionObjectStatic(node, exception); + public int getRawStringLength(Object string) { + return string instanceof WideString ? ((WideString) string).data.length : (int) ((Buffer) string).length; } private static Buffer checkCString(byte[] path) { @@ -3683,7 +3677,7 @@ private PosixException newPosixException(int errno) throws PosixException { @TruffleBoundary private PosixException newPosixException(int errno, Integer winerror) throws PosixException { - throw new PosixErrnoException(errno, strerror(errno, null, NativeMemory.ZeroTerminatedUtf8ToTruffleStringNode.getUncached()), winerror); + throw new PosixErrnoException(errno, strerror(errno), winerror); } // CPython performs this mapping in PC/errmap.h:winerror_to_errno(). @@ -3894,6 +3888,37 @@ private static long stringToNativeUTF8CString(Node node, TruffleString input, return NativeMemory.copyToNativeZeroTerminatedByteArray(utf8, 0, utf8.length); } + @TruffleBoundary + private static byte[] getUTF8StringBytes(Node node, TruffleString str, TruffleString.SwitchEncodingNode switchEncodingNode, + TruffleString.IsValidNode isValidNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { + if (!isValidNode.execute(str, TS_ENCODING)) { + throw raiseSurrogatesEncodeError(node, str); + } + TruffleString utf8 = switchEncodingNode.execute(str, UTF_8); + byte[] bytes = new byte[utf8.byteLength(UTF_8)]; + copyToByteArrayNode.execute(utf8, 0, bytes, 0, bytes.length, UTF_8); + return bytes; + } + + @TruffleBoundary + private static PException raiseSurrogatesEncodeError(Node node, TruffleString str) { + int byteIndex = TruffleString.ByteIndexOfCodePointSetNode.getUncached().execute(str, 0, str.byteLength(TS_ENCODING), SURROGATE_CODE_POINT_SET); + int start = byteIndex < 0 ? 0 : byteIndex / 4; + int length = str.codePointLengthUncached(TS_ENCODING); + int end = Math.min(start + 1, length); + while (end < length) { + int codePoint = str.codePointAtIndexUncached(end, TS_ENCODING); + if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { + break; + } + end++; + } + Object exception = CallNode.executeUncached(PythonBuiltinClassType.UnicodeEncodeError, + PythonUtils.toTruffleStringUncached("utf-8"), str, start, end, + PythonUtils.toTruffleStringUncached("surrogates not allowed")); + return PRaiseNode.raiseExceptionObjectStatic(node, exception); + } + private static long stringToNativeUTF16CString(TruffleString input, TruffleString.SwitchEncodingNode switchEncodingNode, TruffleString.CopyToByteArrayNode copyToByteArrayNode) { @@ -3920,13 +3945,6 @@ private static void checkBounds(byte[] buf, int offset, int length) { } } - @TruffleBoundary - private static void log(Level level, String fmt, Object... args) { - if (LOGGER.isLoggable(level)) { - LOGGER.log(level, String.format(fmt, args)); - } - } - private int getErrno() { return posixNativeFunctionInvoker.get_errno(); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java index 1cf9dde5bf..74cb436a51 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixResources.java @@ -356,7 +356,7 @@ public String getFilePath(int fd) { } @TruffleBoundary - public void close(int fd) { + public void closeResource(int fd) { try { removeFD(fd); } catch (IOException ignored) { @@ -403,12 +403,12 @@ public int dup2(int fd, int fd2) throws IOException { } @TruffleBoundary - public boolean fsync(int fd) { + public boolean hasFsyncResource(int fd) { return files.getOrDefault(fd, null) != null; } @TruffleBoundary - public Object ftruncate(int fd, long size) throws IOException { + public Object ftruncateResource(int fd, long size) throws IOException { Channel channel = getFileChannel(fd); if (channel instanceof SeekableByteChannel) { return ((SeekableByteChannel) channel).truncate(size); @@ -417,7 +417,7 @@ public Object ftruncate(int fd, long size) throws IOException { } @TruffleBoundary - public int[] pipe() throws IOException { + public int[] pipeResource() throws IOException { synchronized (files) { Pipe pipe = Pipe.open(); int readFD = nextFreeFd(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java index 2917505c04..97a5f718e1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -40,10 +40,623 @@ */ package com.oracle.graal.python.runtime; +import static com.oracle.graal.python.runtime.PosixConstants.AF_INET; +import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6; +import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFBLK; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFCHR; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFDIR; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFIFO; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT; +import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; +import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; public abstract class PosixSupport { + + /* + * POSIX operations must have @TruffleBoundary on both their declarations and implementations. + * The declaration prevents partial evaluation of unresolved virtual calls and avoids performance + * warnings. After devirtualization, partial evaluation sees the concrete implementation, which + * needs its own annotation because method annotations are not inherited. TruffleString + * conversions that benefit from partial evaluation belong in PosixSupportNodes, outside these + * boundaries. + */ + + public static final int ST_MODE = 0; + + public static final char POSIX_FILENAME_SEPARATOR = '/'; + + // Constants for accessing the fields of the fstat result: + // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants + public static final int ST_SIZE = 6; + + /** + * Equivalent to struct r_usage with the fields expected on macOS and Linux. + * + * @param ru_utime time in user mode (fractional seconds) + * @param ru_stime time in system mode (fractional seconds) + * @param ru_maxrss reserved memory size + * @param ru_ixrss shared memory size + * @param ru_idrss unshared memory size + * @param ru_isrss unshared stack size + * @param ru_minflt page faults not requiring I/O + * @param ru_majflt page faults requiring I/O + * @param ru_nswap number of swap outs + * @param ru_inblock block input operations + * @param ru_oublock block output operations + * @param ru_msgsnd messages sent + * @param ru_msgrcv messages received + * @param ru_nsignals signals received + * @param ru_nvcsw voluntary context switches + * @param ru_nivcsw involuntary context switches + */ + public record RusageResult(double ru_utime, double ru_stime, + long ru_maxrss, long ru_ixrss, long ru_idrss, long ru_isrss, + long ru_minflt, long ru_majflt, long ru_nswap, long ru_inblock, long ru_oublock, + long ru_msgsnd, long ru_msgrcv, long ru_nsignals, long ru_nvcsw, long ru_nivcsw) { + } + + public record OpenPtyResult(int masterFd, int slaveFd) { + } + + public abstract static class PwdResult { + /** + * This value represents unsigned 64 bit integer. + */ + public final long uid; + + /** + * This value represents unsigned 64 bit integer. + */ + public final long gid; + + protected PwdResult(long uid, long gid) { + this.uid = uid; + this.gid = gid; + } + } + + /** + * Base class for addresses specific to a particular socket family. + * + * The subclasses are simple POJOs whose definitions are common to all backends. They need to be + * converted to {@code UniversalSockAddr} before use. + */ + public abstract static class FamilySpecificSockAddr { + private final int family; + + protected FamilySpecificSockAddr(int family) { + this.family = family; + } + + public int getFamily() { + return family; + } + } + + /** + * A tagged union of all address types which is capable of holding an address of any socket + * family. + * + * An universal socket address keeps the value in a representation used internally by the given + * backend, therefore implementations of this interface are backend-specific (unlike + * {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX + * {@code struct sockaddr_storage}. + * + */ + public interface UniversalSockAddr { + @TruffleBoundary + int getFamily(); + + @TruffleBoundary + Inet4SockAddr asInet4SockAddr(); + + @TruffleBoundary + Inet6SockAddr asInet6SockAddr(); + + @TruffleBoundary + UnixSockAddr asUnixSockAddr(); + } + + /** + * Represents an address for IPv4 sockets (the {@link PosixConstants#AF_INET} socket family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_in} - integer values are + * kept in host byte order, conversion to network order ({@code htons/htonl}) is done + * automatically by the backend. This makes the integer representation of address compatible + * with the {@code INADDR_xxx} constants. On the other hand, addresses represented as byte + * arrays are in network order to make them compatible with {@code inet_pton} and + * {@code inet_ntop}). + */ + @ValueType + public static final class Inet4SockAddr extends FamilySpecificSockAddr { + private final int port; // host order, 0 - 65535 + private final int address; // host order, e.g. INADDR_LOOPBACK + + public Inet4SockAddr(int port, int address) { + super(AF_INET.value); + assert port >= 0 && port <= 65535; + this.port = port; + this.address = address; + } + + public Inet4SockAddr(int port, byte[] address) { + this(port, bytesToInt(address)); + } + + public int getPort() { + return port; + } + + public int getAddress() { + return address; + } + + public byte[] getAddressAsBytes() { + return intToBytes(address); + } + + private static int bytesToInt(byte[] src) { + assert src != null && src.length >= 4; + return ByteArraySupport.bigEndian().getInt(src, 0); + } + + private static byte[] intToBytes(int src) { + byte[] dst = new byte[4]; + ByteArraySupport.bigEndian().putInt(dst, 0, src); + return dst; + } + } + + /** + * Represents an address for IPv6 sockets (the {@link PosixConstants#AF_INET6} socket family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_in6} - the values are kept + * in host byte order, conversion to network order ({@code htons/htonl}) is done automatically + * by the backend. + */ + @ValueType + public static final class Inet6SockAddr extends FamilySpecificSockAddr { + private final int port; // host order, 0 - 65535 + private final byte[] address = new byte[16]; + private final int flowInfo; // host order, 0 - 2^20-1 + private final int scopeId; // host order, interpreted as unsigned + + public Inet6SockAddr(int port, byte[] address, int flowInfo, int scopeId) { + super(AF_INET6.value); + assert port >= 0 && port <= 65535; + assert address != null && address.length == 16; + assert flowInfo >= 0 && flowInfo <= 1048575; + this.port = port; + PythonUtils.arraycopy(address, 0, this.address, 0, 16); + this.flowInfo = flowInfo; + this.scopeId = scopeId; + } + + public int getPort() { + return port; + } + + public byte[] getAddress() { + return Arrays.copyOf(address, 16); + } + + public int getFlowInfo() { + return flowInfo; + } + + public int getScopeId() { + return scopeId; + } + } + + /** + * Represents an address for UNIX domain sockets (the {@link PosixConstants#AF_UNIX} socket + * family). + * + * This is a higher level equivalent of POSIX {@code struct sockaddr_un}, see + * {@code man -7 unix}. It is the responsibility of the user to ensure that pathname addresses + * are zero terminated and abstract addresses start with a zero. + */ + @ValueType + public static final class UnixSockAddr extends FamilySpecificSockAddr { + private final byte[] path; + + public UnixSockAddr(byte[] path) { + super(AF_UNIX.value); + this.path = path; + } + + /** + * Returns the path, which: + *
      + *
    • for unnamed addresses is of length 0,
    • + *
    • for pathname addresses contains the terminating zero,
    • + *
    • for abstract addresses start with a zero,
    • + *
    • should not be modified by the caller.
    • + *
    + */ + public byte[] getPath() { + return path; + } + } + + public static final class AcceptResult { + public final int socketFd; + public final UniversalSockAddr sockAddr; + + public AcceptResult(int socketFd, UniversalSockAddr sockAddr) { + this.socketFd = socketFd; + this.sockAddr = sockAddr; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "RecvfromResult{" + "socketFd=" + socketFd + ", sockAddr=" + sockAddr + '}'; + } + } + + public static final class RecvfromResult { + public final int readBytes; + public final UniversalSockAddr sockAddr; + + public RecvfromResult(int readBytes, UniversalSockAddr sockAddr) { + this.readBytes = readBytes; + this.sockAddr = sockAddr; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "RecvfromResult{" + "readBytes=" + readBytes + ", sockAddr=" + sockAddr + '}'; + } + } + + /** + * Represents one or more addrinfos returned by {@code getaddrinfo()}. + * + * Must be explicitly released using {@link #release()}. + * Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing + * at the first address info). The cursor can only move forward using the + * {@link #next()} method. + */ + public interface AddrInfoCursor { + @TruffleBoundary + void release(); + + @TruffleBoundary + boolean next(); + + @TruffleBoundary + int getFlags(); + + @TruffleBoundary + int getFamily(); + + @TruffleBoundary + int getSockType(); + + @TruffleBoundary + int getProtocol(); + + @TruffleBoundary + Object getCanonName(); + + @TruffleBoundary + UniversalSockAddr getSockAddr(); + } + + /** + * Exception that indicates and error while executing + * {@link PosixSupport#getaddrinfo(Object, Object, int, int, int, int)}. + */ + public static final class GetAddrInfoException extends Exception { + + private static final long serialVersionUID = 3013253817849329391L; + + private final int errorCode; + private final transient TruffleString msg; + + public GetAddrInfoException(int errorCode, TruffleString message) { + super(message.toJavaStringUncached()); + this.errorCode = errorCode; + msg = message; + } + + public int getErrorCode() { + return errorCode; + } + + public final TruffleString getMessageAsTruffleString() { + return msg; + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + /** + * Base class for exceptions that originate in the POSIX support layer. + */ + public abstract static class PosixException extends Exception { + + private static final long serialVersionUID = 8700515065120346760L; + + protected PosixException() { + } + + protected PosixException(String message) { + super(message); + } + + public final boolean hasErrno(OSErrorEnum errno) { + return this instanceof PosixErrnoException errnoException && errnoException.getErrorCode() == errno.getNumber(); + } + + @SuppressWarnings("sync-override") + @Override + public Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that indicates POSIX level error associated with numeric code. If the message is + * known, it may be included in the exception, otherwise it can be queried using + * {@link PosixSupport#strerror(int)}. + */ + public static final class PosixErrnoException extends PosixException { + + private static final long serialVersionUID = -115762483478883093L; + + private final int errorCode; + private final transient TruffleString msg; + /* + * Windows APIs expose both POSIX errno and a native Win32/Winsock error code. Store the + * native code as java.lang.Integer rather than int because most PosixErrnoException + * instances are not backed by a Windows error, so this field can be null. + */ + private final Integer winerror; + + public PosixErrnoException(int errorCode, TruffleString message) { + this(errorCode, message, null); + } + + public PosixErrnoException(int errorCode, TruffleString message, Integer winerror) { + this.errorCode = errorCode; + msg = message; + this.winerror = winerror; + } + + public TruffleString getMessageAsTruffleString() { + return msg; + } + + @Override + public String getMessage() { + return msg.toJavaStringUncached(); + } + + public int getErrorCode() { + return errorCode; + } + + public Integer getWinerror() { + return winerror; + } + } + + /** + * Exception that indicates that a string of characters passed into the {@code inet_aton} or + * {@code inet_pton} function does not represent a valid IP address. These functions do not use + * the usual {@code errno} mechanism to report this kind of errors. + */ + public static class InvalidAddressException extends Exception { + + private static final long serialVersionUID = -2999913421191382026L; + + public InvalidAddressException() { + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that indicates that path for a unix socket was too long. + */ + public static class InvalidUnixSocketPathException extends Exception { + + private static final long serialVersionUID = 3603545222627858084L; + + public static InvalidUnixSocketPathException INSTANCE = new InvalidUnixSocketPathException(); + + private InvalidUnixSocketPathException() { + } + + @SuppressWarnings("sync-override") + @Override + public final Throwable fillInStackTrace() { + return this; + } + } + + /** + * Exception that may be thrown by all the messages. It indicates that given functionality is + * not available in given implementation. In the future, there will be methods to query if + * certain feature is supported or not, but even then this exception may be thrown for other + * features. + */ + public static class UnsupportedPosixFeatureException extends PosixException { + + private static final long serialVersionUID = 1846254827094902593L; + + public UnsupportedPosixFeatureException(String message) { + super(message); + } + } + + /** + * Simple wrapper that allows exchanging byte buffers with the outside world. + */ + @ValueType + public static class Buffer { + public final byte[] data; + public long length; + + public Buffer(byte[] data, long length) { + assert data != null && length >= 0 && length <= data.length; + this.data = data; + this.length = length; + } + + public static Buffer allocate(long capacity) { + if (capacity > Integer.MAX_VALUE) { + throw CompilerDirectives.shouldNotReachHere("Long arrays are not supported yet"); + } + return new Buffer(new byte[(int) capacity], 0); + } + + public static Buffer wrap(byte[] data) { + return new Buffer(data, data.length); + } + + public Buffer withLength(long newLength) { + if (newLength > data.length) { + throw CompilerDirectives.shouldNotReachHere("Actual length cannot be greater than capacity"); + } + length = newLength; + return this; + } + + @TruffleBoundary + public ByteBuffer getByteBuffer() { + return ByteBuffer.wrap(data, 0, (int) length); + } + } + + /** + * Corresponds to the {@code timeval} struct. + */ + @ValueType + public static final class Timeval { + public static final Timeval SELECT_TIMEOUT_NOW = new Timeval(0, 0); + + private final long seconds; + private final long microseconds; + + public Timeval(long seconds, long microseconds) { + this.seconds = seconds; + this.microseconds = microseconds; + } + + public long getSeconds() { + return seconds; + } + + public long getMicroseconds() { + return microseconds; + } + } + + /** + * Wraps boolean arrays that indicate if given file descriptor was selected or not. For example, + * if {@code getReadFds()[X]} is {@code true}, then the file descriptor that was passed to + * {@code select} as {@code readfds[X]} was selected. + */ + @ValueType + public static final class SelectResult { + private final boolean[] readfds; + private final boolean[] writefds; + private final boolean[] errorfds; + + public SelectResult(boolean[] readfds, boolean[] writefds, boolean[] errorfds) { + this.readfds = readfds; + this.writefds = writefds; + this.errorfds = errorfds; + } + + public boolean[] getReadFds() { + return readfds; + } + + public boolean[] getWriteFds() { + return writefds; + } + + public boolean[] getErrorFds() { + return errorfds; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return String.format("select[read = %s; write = %s; err = %s]", Arrays.toString(readfds), Arrays.toString(writefds), Arrays.toString(errorfds)); + } + } + + // from stat.h macros + private static boolean istype(long mode, int mask) { + return (mode & S_IFMT.value) == mask; + } + + public static boolean isDIR(long mode) { + return istype(mode, S_IFDIR.value); + } + + public static boolean isCHR(long mode) { + return istype(mode, S_IFCHR.value); + } + + public static boolean isBLK(long mode) { + return istype(mode, S_IFBLK.value); + } + + public static boolean isREG(long mode) { + return istype(mode, S_IFREG.value); + } + + public static boolean isFIFO(long mode) { + return istype(mode, S_IFIFO.value); + } + + public static boolean isLNK(long mode) { + return istype(mode, S_IFLNK.value); + } + + public static class ChannelNotSelectableException extends UnsupportedPosixFeatureException { + private static final long serialVersionUID = -4185480181939639297L; + static ChannelNotSelectableException INSTANCE = new ChannelNotSelectableException(); + + private ChannelNotSelectableException() { + super(null); + } + } + + public abstract static class Path { + } + public void setEnv(@SuppressWarnings("unused") Env env) { // nop } @@ -51,4 +664,516 @@ public void setEnv(@SuppressWarnings("unused") Env env) { public static PosixSupport get(Node node) { return PythonContext.get(node).getPosixSupport(); } + + @TruffleBoundary + public abstract long semOpen(Object name, int openFlags, int mode, int value) throws PosixException; + + @TruffleBoundary + public final long semOpen(Object name) throws PosixException { + return semOpen(name, 0, 0, 0); + } + + @TruffleBoundary + public abstract void semClose(long handle) throws PosixException; + + @TruffleBoundary + public abstract void semUnlink(Object name) throws PosixException; + + @TruffleBoundary + public abstract int shmOpen(Object name, int openFlags, int mode) throws PosixException; + + @TruffleBoundary + public abstract void shmUnlink(Object name) throws PosixException; + + @TruffleBoundary + public abstract int semGetValue(long handle) throws PosixException; + + @TruffleBoundary + public abstract void semPost(long handle) throws PosixException; + + @TruffleBoundary + public abstract void semWait(long handle) throws PosixException; + + @TruffleBoundary + public abstract boolean semTryWait(long handle) throws PosixException; + + @TruffleBoundary + public abstract boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException; + + /** + * Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may + * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. + */ + @TruffleBoundary + public abstract PwdResult getpwuid(long uid) throws PosixException; + + /** + * Equivalent of POSIX {@code getpwnam_r}. On top of the error codes defined by POSIX, this may + * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. + * + * @param name the name encoded the same way as paths + */ + @TruffleBoundary + public abstract PwdResult getpwnam(Object name) throws PosixException; + + /** + * Availability of {@link #getpwentries()}. If {@code false}, then {@link #getpwentries()} will + * throw {@link UnsupportedPosixFeatureException}. + */ + @TruffleBoundary + public abstract boolean hasGetpwentries(); + + /** + * Returns a list of all entries in the password database. Equivalent of using POSIX functions + * {@code setpwent}, {@code getpwent}, and {@code endpwent}. + */ + @TruffleBoundary + public abstract PwdResult[] getpwentries() throws PosixException; + + /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ + @TruffleBoundary + public abstract Object createCStringFromBytes(byte[] bytes); + + @TruffleBoundary + public abstract int socket(int domain, int type, int protocol) throws PosixException; + + @TruffleBoundary + public abstract AcceptResult accept(int sockfd) throws PosixException; + + @TruffleBoundary + public abstract void bind(int sockfd, UniversalSockAddr addr) throws PosixException; + + @TruffleBoundary + public abstract void connect(int sockfd, UniversalSockAddr addr) throws PosixException; + + @TruffleBoundary + public abstract void listen(int sockfd, int backlog) throws PosixException; + + @TruffleBoundary + public abstract UniversalSockAddr getpeername(int sockfd) throws PosixException; + + @TruffleBoundary + public abstract UniversalSockAddr getsockname(int sockfd) throws PosixException; + + @TruffleBoundary + public abstract int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. + @TruffleBoundary + public abstract int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException; + + @TruffleBoundary + public abstract int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + // For STREAM sockets, the returned address will be AF_UNSPEC + @TruffleBoundary + public abstract RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; + + @TruffleBoundary + public abstract void shutdown(int sockfd, int how) throws PosixException; + + @TruffleBoundary + public abstract int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + + @TruffleBoundary + public abstract void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; + + @TruffleBoundary + public abstract int inet_addr(Object src); + + @TruffleBoundary + public abstract int inet_aton(Object src) throws InvalidAddressException; + + @TruffleBoundary + public abstract Object inet_ntoa(int address); + + @TruffleBoundary + public abstract byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException; + + @TruffleBoundary + public abstract Object inet_ntop(int family, byte[] src) throws PosixException; + + @TruffleBoundary + public abstract Object gethostname() throws PosixException; + + @TruffleBoundary + public abstract Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; + + /** The caller must release the returned cursor exactly once. */ + @TruffleBoundary + public abstract AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) + throws UnsupportedPosixFeatureException, GetAddrInfoException; + + @TruffleBoundary + public abstract int ioctlBytes(int fd, long request, byte[] arg) throws PosixException; + + @TruffleBoundary + public abstract int ioctlInt(int fd, long request, int arg) throws PosixException; + + @TruffleBoundary + public abstract UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src); + + @TruffleBoundary + public abstract UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src); + + @TruffleBoundary + public abstract UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException; + + @TruffleBoundary + public abstract void raise(int signal) throws PosixException; + + @TruffleBoundary + public abstract int alarm(int seconds) throws PosixException; + + @TruffleBoundary + public abstract Timeval[] getitimer(int which) throws PosixException; + + @TruffleBoundary + public abstract Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException; + + @TruffleBoundary + public abstract void signalSelf(int signal) throws PosixException; + + @TruffleBoundary + public abstract void kill(long pid, int signal) throws PosixException; + + @TruffleBoundary + public abstract void killpg(long pid, int signal) throws PosixException; + + @TruffleBoundary + public abstract long[] waitpid(Node location, long pid, int options) throws PosixException; + + @TruffleBoundary + public abstract boolean wcoredump(int status); + + @TruffleBoundary + public abstract boolean wifcontinued(int status); + + @TruffleBoundary + public abstract boolean wifstopped(int status); + + @TruffleBoundary + public abstract boolean wifsignaled(int status); + + @TruffleBoundary + public abstract boolean wifexited(int status); + + @TruffleBoundary + public abstract int wexitstatus(int status); + + @TruffleBoundary + public abstract int wtermsig(int status); + + @TruffleBoundary + public abstract int wstopsig(int status); + + @TruffleBoundary + public abstract long getuid(); + + @TruffleBoundary + public abstract long geteuid() throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract long getgid(); + + @TruffleBoundary + public abstract long getegid() throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract long getppid() throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract long getpgid(long pid) throws PosixException; + + @TruffleBoundary + public abstract void setpgid(long pid, long pgid) throws PosixException; + + @TruffleBoundary + public abstract long getpgrp() throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract long getsid(long pid) throws PosixException; + + @TruffleBoundary + public abstract long setsid() throws PosixException; + + @TruffleBoundary + public abstract long[] getgroups() throws PosixException; + + @TruffleBoundary + public abstract RusageResult getrusage(int who) throws PosixException; + + @TruffleBoundary + public abstract OpenPtyResult openpty() throws PosixException; + + @TruffleBoundary + public abstract Object ctermid() throws PosixException; + + // note: this leaks memory in native backend and is not synchronized + @TruffleBoundary + public abstract void setenv(Object name, Object value, boolean overwrite) throws PosixException; + + @TruffleBoundary + public abstract void unsetenv(Object name) throws PosixException; + + @TruffleBoundary + public abstract int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, + int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, + boolean allowVFork) throws PosixException; + + // args.length must be > 0 + @TruffleBoundary + public abstract void execv(Object pathname, Object[] args) throws PosixException; + + // does not throw, because posix does not exactly define the return value + @TruffleBoundary + public abstract int system(Object command); + + @TruffleBoundary + public abstract Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; + + @TruffleBoundary + public abstract byte mmapReadByte(Object mmap, long index) throws PosixException; + + @TruffleBoundary + public abstract void mmapWriteByte(Object mmap, long index, byte value) throws PosixException; + + @TruffleBoundary + public abstract int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + + @TruffleBoundary + public abstract void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException; + + @TruffleBoundary + public abstract void mmapFlush(Object mmap, long offset, long length) throws PosixException; + + @TruffleBoundary + public abstract void mmapUnmap(Object mmap, long length) throws PosixException; + + @TruffleBoundary + public abstract long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract TruffleString getBackend(); + + @TruffleBoundary + public abstract TruffleString strerror(int errorCode); + + @TruffleBoundary + public abstract long getpid(); + + @TruffleBoundary + public abstract int umask(int mask) throws PosixException; + + @TruffleBoundary + public abstract int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException; + + @TruffleBoundary + public abstract int close(int fd) throws PosixException; + + @TruffleBoundary + public abstract long getOsfHandle(int fd) throws PosixException; + + @TruffleBoundary + public abstract int openOsfHandle(long handle, int flags) throws PosixException; + + @TruffleBoundary + public abstract int setMode(int fd, int mode) throws PosixException; + + @TruffleBoundary + public abstract void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException; + + @TruffleBoundary + public abstract int[] pipe() throws PosixException; + + @TruffleBoundary + public abstract SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; + + @TruffleBoundary + public abstract void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException; + + @TruffleBoundary + public abstract long lseek(int fd, long offset, int how) throws PosixException; + + @TruffleBoundary + public abstract void ftruncate(int fd, long length) throws PosixException; + + @TruffleBoundary + public abstract void truncate(Object path, long length) throws PosixException; + + @TruffleBoundary + public abstract void fsync(int fd) throws PosixException; + + @TruffleBoundary + public abstract void flock(int fd, int operation) throws PosixException; + + @TruffleBoundary + public abstract void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; + + @TruffleBoundary + public abstract boolean getBlocking(int fd) throws PosixException; + + @TruffleBoundary + public abstract void setBlocking(int fd, boolean blocking) throws PosixException; + + @TruffleBoundary + public abstract int[] getTerminalSize(int fd) throws PosixException; + + @TruffleBoundary + public abstract long sysconf(int name) throws PosixException; + + @TruffleBoundary + public abstract Buffer read(int fd, long length) throws PosixException; + + @TruffleBoundary + public abstract long write(int fd, Buffer data) throws PosixException; + + /** Returns {@code 'r'}, {@code 'w'}, or zero when {@code fd} is not a Windows console. */ + @TruffleBoundary + public abstract int getWindowsConsoleType(int fd); + + @TruffleBoundary + public abstract long writeWindowsConsole(int fd, Buffer data) throws PosixException; + + @TruffleBoundary + public abstract int dup(int fd) throws PosixException; + + @TruffleBoundary + public abstract int dup2(int fd, int fd2, boolean inheritable) throws PosixException; + + @TruffleBoundary + public abstract boolean getInheritable(int fd) throws PosixException; + + @TruffleBoundary + public abstract void setInheritable(int fd, boolean inheritable) throws PosixException; + + // see stat_struct_to_longs in posix.c for the layout of the array + @TruffleBoundary + public abstract long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException; + + /** + * Performs operation of fstat(fd). + * + * @param fd the file descriptor + * @return see {@code stat_struct_to_longs} in posix.c for the layout of the array. There are + * constants for some of the indices, e.g., {@link #ST_MODE}. + * @throws PosixException if an error occurs + */ + @TruffleBoundary + public abstract long[] fstat(int fd) throws PosixException; + + @TruffleBoundary + public abstract long[] statvfs(Object path) throws PosixException; + + @TruffleBoundary + public abstract long[] fstatvfs(int fd) throws PosixException; + + @TruffleBoundary + public abstract Object[] uname() throws PosixException; + + public record WindowsVersion(int major, int minor, int build, int platform, TruffleString servicePack, + int servicePackMajor, int servicePackMinor, int suiteMask, int productType, + int platformMajor, int platformMinor, int platformBuild) { + } + + /** Returns the Windows version and product information. */ + @TruffleBoundary + public abstract WindowsVersion getWindowsVersion() throws PosixException; + + @TruffleBoundary + public abstract void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException; + + @TruffleBoundary + public abstract void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException; + + @TruffleBoundary + public abstract void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException; + + @TruffleBoundary + public abstract void mkdirat(int dirFd, Object pathname, int mode) throws PosixException; + + @TruffleBoundary + public abstract Object getcwd() throws PosixException; + + @TruffleBoundary + public abstract void chdir(Object path) throws PosixException; + + @TruffleBoundary + public abstract void fchdir(int fd) throws PosixException; + + @TruffleBoundary + public abstract boolean isatty(int fd); + + /** Caller is responsible for closing the returned directory stream with {@link #closedir(Object)}. */ + @TruffleBoundary + public abstract Object opendir(Object path) throws PosixException; + + @TruffleBoundary + public abstract Object fdopendir(int fd) throws PosixException; + + /** Implementations must deal with this being called more than once. */ + @TruffleBoundary + public abstract void closedir(Object dirStream) throws PosixException; + + /** Returns null when there are no more entries or the stream has been closed. */ + @TruffleBoundary + public abstract Object readdir(Object dirStream) throws PosixException; + + @TruffleBoundary + public abstract void rewinddir(Object dirStream); + + /** Returns an opaque directory-entry name suitable for path conversion. */ + @TruffleBoundary + public abstract Object dirEntryGetName(Object dirEntry) throws PosixException; + + /** Returns the entry name joined to the path originally passed to {@link #opendir(Object)}. */ + @TruffleBoundary + public abstract Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException; + + @TruffleBoundary + public abstract long dirEntryGetInode(Object dirEntry) throws PosixException; + + @TruffleBoundary + public abstract int dirEntryGetType(Object dirEntry); + + /** The timespec contains access seconds/nanoseconds, then modification seconds/nanoseconds, or is null for now. */ + @TruffleBoundary + public abstract void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException; + + @TruffleBoundary + public abstract void futimens(int fd, long[] timespec) throws PosixException; + + /** The timeval is null or contains access and modification times. */ + @TruffleBoundary + public abstract void futimes(int fd, Timeval[] timeval) throws PosixException; + + @TruffleBoundary + public abstract void lutimes(Object filename, Timeval[] timeval) throws PosixException; + + @TruffleBoundary + public abstract void utimes(Object filename, Timeval[] timeval) throws PosixException; + + @TruffleBoundary + public abstract void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + + @TruffleBoundary + public abstract void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; + + @TruffleBoundary + public abstract boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; + + @TruffleBoundary + public abstract void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; + + @TruffleBoundary + public abstract void fchmod(int fd, int mode) throws PosixException; + + @TruffleBoundary + public abstract void fchownat(int dirFd, Object pathname, long owner, long group, boolean followSymlinks) throws PosixException; + + @TruffleBoundary + public abstract void fchown(int fd, long owner, long group) throws PosixException; + + @TruffleBoundary + public abstract Object readlinkat(int dirFd, Object path) throws PosixException; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java deleted file mode 100644 index 1d4ddb47be..0000000000 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java +++ /dev/null @@ -1,1318 +0,0 @@ -/* - * Copyright (c) 2020, 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 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.graal.python.runtime; - -import static com.oracle.graal.python.runtime.PosixConstants.AF_INET; -import static com.oracle.graal.python.runtime.PosixConstants.AF_INET6; -import static com.oracle.graal.python.runtime.PosixConstants.AF_UNIX; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFBLK; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFCHR; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFDIR; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFIFO; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFLNK; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFMT; -import static com.oracle.graal.python.runtime.PosixConstants.S_IFREG; - -import java.nio.ByteBuffer; -import java.util.Arrays; - -import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum; -import com.oracle.graal.python.util.PythonUtils; -import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.CompilerDirectives.ValueType; -import com.oracle.truffle.api.library.GenerateLibrary; -import com.oracle.truffle.api.library.Library; -import com.oracle.truffle.api.library.LibraryFactory; -import com.oracle.truffle.api.memory.ByteArraySupport; -import com.oracle.truffle.api.strings.TruffleString; - -/** - * Internal abstraction layer for POSIX functionality. Instance of the implementation is stored in - * the context. Use {@link PythonContext#getPosixSupport()} to access it. - */ -@GenerateLibrary(receiverType = PosixSupport.class) -public abstract class PosixSupportLibrary extends Library { - - public static final char POSIX_FILENAME_SEPARATOR = '/'; - - // Constants for accessing the fields of the fstat result: - // TODO: have these in posix.c (maybe posix.h) and extract them along with other constants - public static final int ST_MODE = 0; - public static final int ST_SIZE = 6; - - public abstract TruffleString getBackend(Object recevier); - - public abstract TruffleString strerror(Object receiver, int errorCode); - - public abstract long getpid(Object receiver); - - public abstract int umask(Object receiver, int mask) throws PosixException; - - public abstract int openat(Object receiver, int dirFd, Object pathname, int flags, int mode) throws PosixException; - - public abstract int close(Object receiver, int fd) throws PosixException; - - public abstract Buffer read(Object receiver, int fd, long length) throws PosixException; - - public abstract long write(Object receiver, int fd, Buffer data) throws PosixException; - - public abstract int dup(Object receiver, int fd) throws PosixException; - - public abstract int dup2(Object receiver, int fd, int fd2, boolean inheritable) throws PosixException; - - public abstract boolean getInheritable(Object receiver, int fd) throws PosixException; - - public abstract void setInheritable(Object receiver, int fd, boolean inheritable) throws PosixException; - - public abstract long getOsfHandle(Object receiver, int fd) throws PosixException; - - public abstract int openOsfHandle(Object receiver, long handle, int flags) throws PosixException; - - public abstract int setMode(Object receiver, int fd, int mode) throws PosixException; - - public abstract void msvcrtLocking(Object receiver, int fd, int mode, long nbytes) throws PosixException; - - public abstract int[] pipe(Object receiver) throws PosixException; - - public abstract SelectResult select(Object receiver, int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException; - - public abstract void poll(Object receiver, int[] fds, int[] events, int[] revents, int timeout) throws PosixException; - - public abstract long lseek(Object receiver, int fd, long offset, int how) throws PosixException; - - public abstract void ftruncate(Object receiver, int fd, long length) throws PosixException; - - public abstract void truncate(Object receiver, Object path, long length) throws PosixException; - - public abstract void fsync(Object receiver, int fd) throws PosixException; - - public abstract void flock(Object receiver, int fd, int operation) throws PosixException; - - public abstract void fcntlLock(Object receiver, int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException; - - public abstract boolean getBlocking(Object receiver, int fd) throws PosixException; - - public abstract void setBlocking(Object receiver, int fd, boolean blocking) throws PosixException; - - public abstract int[] getTerminalSize(Object receiver, int fd) throws PosixException; - - public abstract long sysconf(Object receiver, int name) throws PosixException; - - // see stat_struct_to_longs in posix.c for the layout of the array - public abstract long[] fstatat(Object receiver, int dirFd, Object pathname, boolean followSymlinks) throws PosixException; - - /** - * Performs operation of fstat(fd). - * - * @param receiver the receiver of the message - * @param fd the file descriptor - * @return see {@code stat_struct_to_longs} in posix.c for the layout of the array. There are - * constants for some of the indices, e.g., {@link #ST_MODE}. - * @throws PosixException if an error occurs - */ - public abstract long[] fstat(Object receiver, int fd) throws PosixException; - - public abstract long[] statvfs(Object receiver, Object path) throws PosixException; - - public abstract long[] fstatvfs(Object receiver, int fd) throws PosixException; - - public abstract Object[] uname(Object receiver) throws PosixException; - - public record WindowsVersion(int major, int minor, int build, int platform, TruffleString servicePack, - int servicePackMajor, int servicePackMinor, int suiteMask, int productType, - int platformMajor, int platformMinor, int platformBuild) { - } - - /** Returns the Windows version and product information. */ - public abstract WindowsVersion getWindowsVersion(Object receiver) throws PosixException; - - public abstract void unlinkat(Object receiver, int dirFd, Object pathname, boolean rmdir) throws PosixException; - - public abstract void linkat(Object receiver, int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException; - - public abstract void symlinkat(Object receiver, Object target, int linkpathDirFd, Object linkpath) throws PosixException; - - public abstract void mkdirat(Object receiver, int dirFd, Object pathname, int mode) throws PosixException; - - public abstract Object getcwd(Object receiver) throws PosixException; - - public abstract void chdir(Object receiver, Object path) throws PosixException; - - /** - * Performs operation of fchdir(fd). - * - * @param receiver the receiver of the message - * @param fd the file descriptor - * @throws PosixException if an error occurs - */ - public abstract void fchdir(Object receiver, int fd) throws PosixException; - - public abstract boolean isatty(Object receiver, int fd); - - /** - * Caller is responsible for calling {@link #closedir(Object, Object)} to free the allocated - * resources. - * - * @return an opaque directory stream object to be used in calls to {@code readdir} and - * {@code closedir} - */ - public abstract Object opendir(Object receiver, Object path) throws PosixException; - - public abstract Object fdopendir(Object receiver, int fd) throws PosixException; - - /** - * Implementations must deal with this being called more than once. - */ - public abstract void closedir(Object receiver, Object dirStream) throws PosixException; - - /** - * @return an opaque dir entry object to be used in calls to {@code dirEntry*()} methods or - * {@code null} when there are no more items or if the stream has been closed by - * {@code closedir}. - */ - public abstract Object readdir(Object receiver, Object dirStream) throws PosixException; - - public abstract void rewinddir(Object receiver, Object dirStream); - - /** - * @return an opaque object representing the dir entry name - * @see #getPathAsBytes(Object, Object) - * @see #getPathAsString(Object, Object) - */ - public abstract Object dirEntryGetName(Object receiver, Object dirEntry) throws PosixException; - - /** - * Returns the dir entry path, which is the name of the dir entry joined with the given path. - * - * @param scandirPath the path originally passed to {@link #opendir(Object, Object)} - * @return an opaque object representing the dir entry path - * @see #getPathAsBytes(Object, Object) - * @see #getPathAsString(Object, Object) - */ - public abstract Object dirEntryGetPath(Object receiver, Object dirEntry, Object scandirPath) throws PosixException; - - public abstract long dirEntryGetInode(Object receiver, Object dirEntry) throws PosixException; - - /** - * @return one of the {@code DT_xxx} constants - */ - public abstract int dirEntryGetType(Object receiver, Object dirEntry); - - /** - * Equivalent of POSIX {@code utimensat()}. - * - * @param timespec an array of 4 longs in this order: - * {@code atime.tv_sec, atime.tv_nsec, mtime.tv_sec, mtime.tv_nsec} or {@code null} - * to set both times to 'now' TODO change long[] timespec to Timespec[] timespec - */ - public abstract void utimensat(Object receiver, int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException; - - /** - * Equivalent of POSIX {@code futimens()}. - */ - public abstract void futimens(Object receiver, int fd, long[] timespec) throws PosixException; - - /** - * @param timeval either {@code null} or has two elements: access time and modification time - */ - public abstract void futimes(Object receiver, int fd, Timeval[] timeval) throws PosixException; - - public abstract void lutimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException; - - public abstract void utimes(Object receiver, Object filename, Timeval[] timeval) throws PosixException; - - public abstract void renameat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; - - public abstract void replaceat(Object receiver, int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException; - - public abstract boolean faccessat(Object receiver, int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException; - - public abstract void fchmodat(Object receiver, int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException; - - public abstract void fchmod(Object receiver, int fd, int mode) throws PosixException; - - public abstract void fchownat(Object receiver, int dirFd, Object pathname, long owner, long group, boolean followSymlinks) throws PosixException; - - public abstract void fchown(Object receiver, int fd, long owner, long group) throws PosixException; - - public abstract Object readlinkat(Object receiver, int dirFd, Object path) throws PosixException; - - public abstract void raise(Object receiver, int signal) throws PosixException; - - public abstract int alarm(Object receiver, int seconds) throws PosixException; - - public abstract Timeval[] getitimer(Object receiver, int which) throws PosixException; - - public abstract Timeval[] setitimer(Object receiver, int which, Timeval delay, Timeval interval) throws PosixException; - - public abstract void signalSelf(Object receiver, int signal) throws PosixException; - - public abstract void kill(Object receiver, long pid, int signal) throws PosixException; - - public abstract void killpg(Object receiver, long pid, int signal) throws PosixException; - - public abstract long[] waitpid(Object receiver, long pid, int options) throws PosixException; - - public abstract boolean wcoredump(Object receiver, int status); - - public abstract boolean wifcontinued(Object receiver, int status); - - public abstract boolean wifstopped(Object receiver, int status); - - public abstract boolean wifsignaled(Object receiver, int status); - - public abstract boolean wifexited(Object receiver, int status); - - public abstract int wexitstatus(Object receiver, int status); - - public abstract int wtermsig(Object receiver, int status); - - public abstract int wstopsig(Object receiver, int status); - - public abstract long getuid(Object receiver); - - public abstract long geteuid(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getgid(Object receiver); - - public abstract long getegid(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getppid(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getpgid(Object receiver, long pid) throws PosixException; - - public abstract void setpgid(Object receiver, long pid, long pgid) throws PosixException; - - public abstract long getpgrp(Object receiver) throws UnsupportedPosixFeatureException; - - public abstract long getsid(Object receiver, long pid) throws PosixException; - - public abstract long setsid(Object receiver) throws PosixException; - - public abstract long[] getgroups(Object receiver) throws PosixException; - - /** - * Equivalent to struct r_usage with the fields expected on macOS and Linux. - * - * @param ru_utime time in user mode (fractional seconds) - * @param ru_stime time in system mode (fractional seconds) - * @param ru_maxrss reserved memory size - * @param ru_ixrss shared memory size - * @param ru_idrss unshared memory size - * @param ru_isrss unshared stack size - * @param ru_minflt page faults not requiring I/O - * @param ru_majflt page faults requiring I/O - * @param ru_nswap number of swap outs - * @param ru_inblock block input operations - * @param ru_oublock block output operations - * @param ru_msgsnd messages sent - * @param ru_msgrcv messages received - * @param ru_nsignals signals received - * @param ru_nvcsw voluntary context switches - * @param ru_nivcsw involuntary context switches - */ - public record RusageResult(double ru_utime, double ru_stime, - long ru_maxrss, long ru_ixrss, long ru_idrss, long ru_isrss, - long ru_minflt, long ru_majflt, long ru_nswap, long ru_inblock, long ru_oublock, - long ru_msgsnd, long ru_msgrcv, long ru_nsignals, long ru_nvcsw, long ru_nivcsw) { - } - - public abstract RusageResult getrusage(Object receiver, int who) throws PosixException; - - public record OpenPtyResult(int masterFd, int slaveFd) { - } - - public abstract OpenPtyResult openpty(Object receiver) throws PosixException; - - public abstract TruffleString ctermid(Object receiver) throws PosixException; - - // note: this leaks memory in native backend and is not synchronized - // TODO is it worth synchronizing at least all accesses made through PosixSupportLibrary? - public abstract void setenv(Object receiver, Object name, Object value, boolean overwrite) throws PosixException; - - public abstract void unsetenv(Object receiver, Object name) throws PosixException; - - public abstract int forkExec(Object receiver, Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, - int stderrReadFd, int stderrWriteFd, int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, - boolean allowVFork) throws PosixException; - - // args.length must be > 0 - public abstract void execv(Object receiver, Object pathname, Object[] args) throws PosixException; - - // does not throw, because posix does not exactly define the return value - public abstract int system(Object receiver, Object command); - - public abstract Object mmap(Object receiver, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException; - - public abstract byte mmapReadByte(Object receiver, Object mmap, long index) throws PosixException; - - public abstract void mmapWriteByte(Object receiver, Object mmap, long index, byte value) throws PosixException; - - public abstract int mmapReadBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException; - - public abstract void mmapWriteBytes(Object receiver, Object mmap, long index, byte[] bytes, int length) throws PosixException; - - public abstract void mmapFlush(Object receiver, Object mmap, long offset, long length) throws PosixException; - - public abstract void mmapUnmap(Object receiver, Object mmap, long length) throws PosixException; - - public abstract long mmapGetPointer(Object receiver, Object mmap) throws UnsupportedPosixFeatureException; - - public abstract long semOpen(Object receiver, Object name, int openFlags, int mode, int value) throws PosixException; - - public final long semOpen(Object receiver, Object name) throws PosixException { - return semOpen(receiver, name, 0, 0, 0); - } - - public abstract void semClose(Object receiver, long handle) throws PosixException; - - public abstract void semUnlink(Object receiver, Object name) throws PosixException; - - public abstract int shmOpen(Object receiver, Object name, int openFlags, int mode) throws PosixException; - - public abstract void shmUnlink(Object receiver, Object name) throws PosixException; - - public abstract int semGetValue(Object receiver, long handle) throws PosixException; - - public abstract void semPost(Object receiver, long handle) throws PosixException; - - public abstract void semWait(Object receiver, long handle) throws PosixException; - - public abstract boolean semTryWait(Object receiver, long handle) throws PosixException; - - public abstract boolean semTimedWait(Object receiver, long handle, long deadlineNs) throws PosixException; - - public static final class PwdResult { - public final TruffleString name; - /** - * This value represents unsigned 64 bit integer. - */ - public final long uid; - /** - * This value represents unsigned 64 bit integer. - */ - public final long gid; - public final TruffleString dir; - public final TruffleString shell; - - public PwdResult(TruffleString name, long uid, long gid, TruffleString dir, TruffleString shell) { - this.name = name; - this.uid = uid; - this.gid = gid; - this.dir = dir; - this.shell = shell; - } - - @Override - public String toString() { - return "PwdResult{name='" + name + '\'' + - ", uid=" + uid + - ", gid=" + gid + - ", dir='" + dir + '\'' + - ", shell='" + shell + "'}"; - } - } - - /** - * Equivalent of POSIX {@code getpwuid_r}. On top of the error codes defined by POSIX, this may - * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. - */ - public abstract PwdResult getpwuid(Object receiver, long uid) throws PosixException; - - /** - * Equivalent of POSIX {@code getpwnam_r}. On top of the error codes defined by POSIX, this may - * also throw {@code ENOMEM}. Returns {@code null} if no matching entry was found. - * - * @param receiver the receiver of the message - * @param name the name encoded the same way as paths - */ - public abstract PwdResult getpwnam(Object receiver, Object name) throws PosixException; - - /** - * Availability of {@link #getpwentries(Object)}. If {@code false}, then - * {@link #getpwentries(Object)} will throw {@link UnsupportedPosixFeatureException}. - */ - public abstract boolean hasGetpwentries(Object receiver); - - /** - * Returns a list of all entries in the password database. Equivalent of using POSIX functions - * {@code setpwent}, {@code getpwent}, and {@code endpwent}. - */ - public abstract PwdResult[] getpwentries(Object receiver) throws PosixException; - - /** - * Converts a {@code TruffleString} into the internal representation of paths used by the - * library implementation. The implementation should return {@code null} if the path after any - * necessary conversion contains embedded null characters. - * - * @param receiver the receiver of the message - * @param path the path as a {@code TruffleString} - * @return an opaque object representing the path or {@code null} if the path contains null - * characters - */ - public abstract Object createPathFromString(Object receiver, TruffleString path); - - /** - * Converts a {@code byte} array into the internal representation of paths used by the library - * implementation. The implementation should return {@code null} if the path after any necessary - * conversion contains embedded null characters. - * - * @param receiver the receiver of the message - * @param path the path as a a {@code byte[]} array - * @return an opaque object representing the path or {@code null} if the path contains null - * characters - */ - public abstract Object createPathFromBytes(Object receiver, byte[] path); - - public abstract TruffleString getPathAsString(Object receiver, Object path); - - public abstract Buffer getPathAsBytes(Object receiver, Object path); - - /** Converts a string to strict UTF-8 for non-filesystem APIs that use CPython's {@code s} conversion. */ - public abstract Object createCStringFromString(Object receiver, TruffleString string); - - /** Wraps already-encoded bytes for narrow native APIs without applying a filesystem conversion. */ - public abstract Object createCStringFromBytes(Object receiver, byte[] bytes); - - /** Converts a string to the UTF-16 representation used by Windows wide-character APIs. */ - public abstract Object createWideStringFromString(Object receiver, TruffleString string); - - public abstract TruffleString getCStringAsString(Object receiver, Object string); - - public abstract Buffer getCStringAsBytes(Object receiver, Object string); - - // region Socket addresses - - /** - * Base class for addresses specific to a particular socket family. - * - * The subclasses are simple POJOs whose definitions are common to all backends. They need to be - * converted to {@code UniversalSockAddr} before use. - */ - public abstract static class FamilySpecificSockAddr { - private final int family; - - protected FamilySpecificSockAddr(int family) { - this.family = family; - } - - public int getFamily() { - return family; - } - } - - /** - * A tagged union of all address types which is capable of holding an address of any socket - * family. - * - * An universal socket address keeps the value in a representation used internally by the given - * backend, therefore implementations of this interface are backend-specific (unlike - * {@link FamilySpecificSockAddr} subclasses). This interface roughly corresponds to POSIX - * {@code struct sockaddr_storage}. - * - * @see UniversalSockAddrLibrary - */ - public interface UniversalSockAddr { - } - - /** - * Represents an address for IPv4 sockets (the {@link PosixConstants#AF_INET} socket family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_in} - integer values are - * kept in host byte order, conversion to network order ({@code htons/htonl}) is done - * automatically by the backend. This makes the integer representation of address compatible - * with the {@code INADDR_xxx} constants. On the other hand, addresses represented as byte - * arrays are in network order to make them compatible with {@code inet_pton} and - * {@code inet_ntop}). - */ - @ValueType - public static final class Inet4SockAddr extends FamilySpecificSockAddr { - private final int port; // host order, 0 - 65535 - private final int address; // host order, e.g. INADDR_LOOPBACK - - public Inet4SockAddr(int port, int address) { - super(AF_INET.value); - assert port >= 0 && port <= 65535; - this.port = port; - this.address = address; - } - - public Inet4SockAddr(int port, byte[] address) { - this(port, bytesToInt(address)); - } - - public int getPort() { - return port; - } - - public int getAddress() { - return address; - } - - public byte[] getAddressAsBytes() { - return intToBytes(address); - } - - private static int bytesToInt(byte[] src) { - assert src != null && src.length >= 4; - return ByteArraySupport.bigEndian().getInt(src, 0); - } - - private static byte[] intToBytes(int src) { - byte[] dst = new byte[4]; - ByteArraySupport.bigEndian().putInt(dst, 0, src); - return dst; - } - } - - /** - * Represents an address for IPv6 sockets (the {@link PosixConstants#AF_INET6} socket family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_in6} - the values are kept - * in host byte order, conversion to network order ({@code htons/htonl}) is done automatically - * by the backend. - */ - @ValueType - public static final class Inet6SockAddr extends FamilySpecificSockAddr { - private final int port; // host order, 0 - 65535 - private final byte[] address = new byte[16]; - private final int flowInfo; // host order, 0 - 2^20-1 - private final int scopeId; // host order, interpreted as unsigned - - public Inet6SockAddr(int port, byte[] address, int flowInfo, int scopeId) { - super(AF_INET6.value); - assert port >= 0 && port <= 65535; - assert address != null && address.length == 16; - assert flowInfo >= 0 && flowInfo <= 1048575; - this.port = port; - PythonUtils.arraycopy(address, 0, this.address, 0, 16); - this.flowInfo = flowInfo; - this.scopeId = scopeId; - } - - public int getPort() { - return port; - } - - public byte[] getAddress() { - return Arrays.copyOf(address, 16); - } - - public int getFlowInfo() { - return flowInfo; - } - - public int getScopeId() { - return scopeId; - } - } - - /** - * Represents an address for UNIX domain sockets (the {@link PosixConstants#AF_UNIX} socket - * family). - * - * This is a higher level equivalent of POSIX {@code struct sockaddr_un}, see - * {@code man -7 unix}. It is the responsibility of the user to ensure that pathname addresses - * are zero terminated and abstract addresses start with a zero. - */ - @ValueType - public static final class UnixSockAddr extends FamilySpecificSockAddr { - private final byte[] path; - - public UnixSockAddr(byte[] path) { - super(AF_UNIX.value); - this.path = path; - } - - /** - * Returns the path, which: - *
      - *
    • for unnamed addresses is of length 0,
    • - *
    • for pathname addresses contains the terminating zero,
    • - *
    • for abstract addresses start with a zero,
    • - *
    • should not be modified by the caller.
    • - *
    - */ - public byte[] getPath() { - return path; - } - } - - // endregion - - // region socket messages - - /** - * Creates a new socket. - * - * @see "socket(2) man pages" - * @see PosixConstants - */ - public abstract int socket(Object receiver, int domain, int type, int protocol) throws PosixException; - - public abstract AcceptResult accept(Object receiver, int sockfd) throws PosixException; - - public abstract void bind(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException; - - public abstract void connect(Object receiver, int sockfd, UniversalSockAddr addr) throws PosixException; - - public abstract void listen(Object receiver, int sockfd, int backlog) throws PosixException; - - public abstract UniversalSockAddr getpeername(Object receiver, int sockfd) throws PosixException; - - public abstract UniversalSockAddr getsockname(Object receiver, int sockfd) throws PosixException; - - public abstract int send(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - - // Unlike POSIX sendto(), we don't support destAddr == null. Use plain send instead. - public abstract int sendto(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException; - - public abstract int recv(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - - // For STREAM sockets, the returned address will be AF_UNSPEC - public abstract RecvfromResult recvfrom(Object receiver, int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException; - - public static final class AcceptResult { - public final int socketFd; - public final UniversalSockAddr sockAddr; - - public AcceptResult(int socketFd, UniversalSockAddr sockAddr) { - this.socketFd = socketFd; - this.sockAddr = sockAddr; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return "RecvfromResult{" + "socketFd=" + socketFd + ", sockAddr=" + sockAddr + '}'; - } - } - - public static final class RecvfromResult { - public final int readBytes; - public final UniversalSockAddr sockAddr; - - public RecvfromResult(int readBytes, UniversalSockAddr sockAddr) { - this.readBytes = readBytes; - this.sockAddr = sockAddr; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return "RecvfromResult{" + "readBytes=" + readBytes + ", sockAddr=" + sockAddr + '}'; - } - } - - public abstract void shutdown(Object receiver, int sockfd, int how) throws PosixException; - - /** - * @param optval buffer for the option value - * @param optlen size of the buffer // TODO use optval.length instead? See also recv, - * mmapReadBytes, read and GR-29856 - * @return the actual size of the value returned - */ - public abstract int getsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; - - public abstract void setsockopt(Object receiver, int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException; - - // endregion - - // region Name resolution messages - - /** - * Corresponds to POSIX {@code inet_addr} function, but the address is returned in host byte - * order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any - * further conversions. If the input is invalid, the native function returns - * {@link PosixConstants#INADDR_NONE}, which is also returned when the input is - * {@code 255.255.255.255}. Since it is not possible to tell whether an error occurred, this - * message does not throw exception and leaves the decision to the caller who might have more - * information. - * - * @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return address in host byte order or {@link PosixConstants#INADDR_NONE} if the input is - * invalid - * @see "inet(3) man pages" - */ - public abstract int inet_addr(Object receiver, Object src); - - /** - * Corresponds to POSIX {@code inet_aton} function, but the address is returned in host byte - * order (and is signed) so that it can be used in {@link Inet4SockAddr} directly without any - * further conversions. - * - * @param src the IPv4 address in numbers-and-dots notation (converted to opaque object using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return address in host byte order - * @throws InvalidAddressException if {@code cp} is not a valid representation of an IPv4 - * address - * @see "inet(3) man pages" - */ - public abstract int inet_aton(Object receiver, Object src) throws InvalidAddressException; - - /** - * Corresponds to POSIX {@code inet_ntoa} function, but the address is expected in host byte - * order (and is signed) for consistency with other messages. - * - * @param address tha IPv4 address in host byte order - * @return opaque string in IPv4 dotted-decimal notation to be converted using - * {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @see "inet(3) man pages" - */ - public abstract Object inet_ntoa(Object receiver, int address); - - /** - * Corresponds to POSIX {@code inet_pton} function. - * - * @param family {@code AF_INET} or {@code AF_INET6} - * @param src opaque string (converted using {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)}) - * @return the binary address in network order (4 bytes for {@code AF_INET}, 16 bytes for - * {@code AF_INET6}) - * @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported - * @throws InvalidAddressException if {@code src} is not a valid representation of an address of - * given family - */ - public abstract byte[] inet_pton(Object receiver, int family, Object src) throws PosixException, InvalidAddressException; - - /** - * Corresponds to POSIX {@code inet_ntop} function. - * - * @param family {@code AF_INET} or {@code AF_INET6} - * @param src the address in network order, must be at least 4 (for {@code AF_INET}) or 16 (for - * {@code AF_INET6}) bytes long, extra bytes are ignored - * @return an opaque string to be converted using {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @throws PosixException with {@code EAFNOSUPPORT} if the {@code family} is not supported - * @throws IllegalArgumentException if {@code src} does not satisfy the requirements stated - * above - */ - public abstract Object inet_ntop(Object receiver, int family, byte[] src) throws PosixException; - - /** - * @return an opaque string to be converted using {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - */ - public abstract Object gethostname(Object receiver) throws PosixException; - - /** - * Corresponds to POSIX {@code getnameinfo(3)}, except it always retrieves both host and service - * names. - * - * @param addr socket address to convert - * @param flags a combination of {@code NI_xxx} flags - * @return an array of two (host, service) opaque strings to be converted using - * {@link #getCStringAsString(Object, Object)} or - * {@link #getCStringAsBytes(Object, Object)} - * @throws GetAddrInfoException when an error occurs (PosixException is not thrown because - * getnameinfo uses its own error codes and gai_strerror instead of the usual errno - * and strerror) - */ - public abstract Object[] getnameinfo(Object receiver, UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException; - - /** - * Corresponds to POSIX {@code getaddrinfo(3)}, except it always passes a non-null value for the - * {@code hints} parameter. - * - * @param node {@code null} or the host name converted using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)} - * @param service {@code null} or the service name converted using - * {@link #createCStringFromBytes(Object, byte[])} or - * {@link #createCStringFromString(Object, TruffleString)} - * @param family one of the {@code AF_xxx} constants, or {@link PosixConstants#AF_UNSPEC} to get - * addresses of any family - * @param sockType one of the {@code SOCK_xxx} constants, or 0 to get addresses of any type - * @param protocol 0 to get addresses with any protocol - * @param flags bitwise OR of {@code AI_xxx} constants - * @return an object representing one or more {@code struct addrinfo}s, which must be explicitly - * released by the caller - * @throws GetAddrInfoException when an error occurs (PosixException is not thrown because - * getaddrinfo uses its own error codes and gai_strerror instead of the usual errno - * and strerror) - */ - public abstract AddrInfoCursor getaddrinfo(Object receiver, Object node, Object service, int family, int sockType, int protocol, int flags) - throws UnsupportedPosixFeatureException, GetAddrInfoException; - - /** - * Represents one or more addrinfos returned by {@code getaddrinfo()}. - * - * Must be explicitly released using {@link AddrInfoCursorLibrary#release(AddrInfoCursor)}. - * Behaves like a cursor which points to a {@code struct addrinfo} structure (initially pointing - * at the first address info). The cursor can only move forward using the - * {@link AddrInfoCursorLibrary#next(AddrInfoCursor)} message. - * - * @see AddrInfoCursorLibrary - */ - public interface AddrInfoCursor { - } - - public abstract int ioctlBytes(Object receiver, int fd, long request, byte[] arg) throws PosixException; - - public abstract int ioctlInt(Object receiver, int fd, long request, int arg) throws PosixException; - - /** - * Provides messages for manipulating {@link AddrInfoCursor}. - */ - @GenerateLibrary - public abstract static class AddrInfoCursorLibrary extends Library { - - protected AddrInfoCursorLibrary() { - } - - /** - * Releases resources associated with the results of {@code getaddrinfo()}. - * - * This must be called exactly once on all instances returned from - * {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}. Released instances can - * no longer be used for any purpose. - */ - public abstract void release(AddrInfoCursor receiver); - - /** - * Moves the cursor to the next address info. - * - * @return false if there are no more address infos in which case the cursor keeps pointing - * to the last item - */ - public abstract boolean next(AddrInfoCursor receiver); - - public abstract int getFlags(AddrInfoCursor receiver); - - public abstract int getFamily(AddrInfoCursor receiver); - - public abstract int getSockType(AddrInfoCursor receiver); - - public abstract int getProtocol(AddrInfoCursor receiver); - - /** - * @return {@code null} or opaque name to be converted using - * {@link PosixSupportLibrary#getPathAsString(Object, Object)} or - * {@link PosixSupportLibrary#getPathAsBytes(Object, Object)} - */ - public abstract Object getCanonName(AddrInfoCursor receiver); - - public abstract UniversalSockAddr getSockAddr(AddrInfoCursor receiver); - - static final LibraryFactory FACTORY = LibraryFactory.resolve(AddrInfoCursorLibrary.class); - - public static LibraryFactory getFactory() { - return FACTORY; - } - - public static AddrInfoCursorLibrary getUncached() { - return FACTORY.getUncached(); - } - } - - /** - * Exception that indicates and error while executing - * {@link #getaddrinfo(Object, Object, Object, int, int, int, int)}. - */ - public static final class GetAddrInfoException extends Exception { - - private static final long serialVersionUID = 3013253817849329391L; - - private final int errorCode; - private final transient TruffleString msg; - - public GetAddrInfoException(int errorCode, TruffleString message) { - super(message.toJavaStringUncached()); - this.errorCode = errorCode; - msg = message; - } - - public int getErrorCode() { - return errorCode; - } - - public final TruffleString getMessageAsTruffleString() { - return msg; - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - // endregion - - /** - * Allocates a new {@link UniversalSockAddr} and initializes it with the provided address. - */ - public abstract UniversalSockAddr createUniversalSockAddrInet4(Object receiver, Inet4SockAddr src); - - public abstract UniversalSockAddr createUniversalSockAddrInet6(Object receiver, Inet6SockAddr src); - - public abstract UniversalSockAddr createUniversalSockAddrUnix(Object receiver, UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException; - - /** - * Provides messages for manipulating {@link UniversalSockAddr}. - */ - @GenerateLibrary - public abstract static class UniversalSockAddrLibrary extends Library { - - protected UniversalSockAddrLibrary() { - } - - /** - * Returns the socket family of the address (one of the {@code AF_xxx} values defined in - * {@link PosixConstants}). - */ - public abstract int getFamily(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_INET} family) into a {@link Inet4SockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_INET} - */ - public abstract Inet4SockAddr asInet4SockAddr(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_INET6} family) into a {@link Inet6SockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_INET6} - */ - public abstract Inet6SockAddr asInet6SockAddr(UniversalSockAddr receiver); - - /** - * Converts the address represented by the receiver (which must be of the - * {@link PosixConstants#AF_UNIX} family) into a {@link UnixSockAddr} instance. - * - * @throws IllegalArgumentException if the socket family of the address is not - * {@link PosixConstants#AF_UNIX} - */ - public abstract UnixSockAddr asUnixSockAddr(UniversalSockAddr receiver); - - static final LibraryFactory FACTORY = LibraryFactory.resolve(UniversalSockAddrLibrary.class); - - public static LibraryFactory getFactory() { - return FACTORY; - } - - public static UniversalSockAddrLibrary getUncached() { - return FACTORY.getUncached(); - } - } - - /** - * Base class for exceptions that originate in the POSIX support layer. - */ - public abstract static class PosixException extends Exception { - - private static final long serialVersionUID = 8700515065120346760L; - - protected PosixException() { - } - - protected PosixException(String message) { - super(message); - } - - public final boolean hasErrno(OSErrorEnum errno) { - return this instanceof PosixErrnoException errnoException && errnoException.getErrorCode() == errno.getNumber(); - } - - @SuppressWarnings("sync-override") - @Override - public Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that indicates POSIX level error associated with numeric code. If the message is - * known, it may be included in the exception, otherwise it can be queried using - * {@link #strerror(Object, int)}. - */ - public static final class PosixErrnoException extends PosixException { - - private static final long serialVersionUID = -115762483478883093L; - - private final int errorCode; - private final transient TruffleString msg; - /* - * Windows APIs expose both POSIX errno and a native Win32/Winsock error code. Store the - * native code as java.lang.Integer rather than int because most PosixErrnoException - * instances are not backed by a Windows error, so this field can be null. - */ - private final Integer winerror; - - public PosixErrnoException(int errorCode, TruffleString message) { - this(errorCode, message, null); - } - - public PosixErrnoException(int errorCode, TruffleString message, Integer winerror) { - this.errorCode = errorCode; - msg = message; - this.winerror = winerror; - } - - public TruffleString getMessageAsTruffleString() { - return msg; - } - - @Override - public String getMessage() { - return msg.toJavaStringUncached(); - } - - public int getErrorCode() { - return errorCode; - } - - public Integer getWinerror() { - return winerror; - } - } - - /** - * Exception that indicates that a string of characters passed into the {@code inet_aton} or - * {@code inet_pton} function does not represent a valid IP address. These functions do not use - * the usual {@code errno} mechanism to report this kind of errors. - */ - public static class InvalidAddressException extends Exception { - - private static final long serialVersionUID = -2999913421191382026L; - - public InvalidAddressException() { - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that indicates that path for a unix socket was too long. - */ - public static class InvalidUnixSocketPathException extends Exception { - - private static final long serialVersionUID = 3603545222627858084L; - - public static InvalidUnixSocketPathException INSTANCE = new InvalidUnixSocketPathException(); - - private InvalidUnixSocketPathException() { - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return this; - } - } - - /** - * Exception that may be thrown by all the messages. It indicates that given functionality is - * not available in given implementation. In the future, there will be methods to query if - * certain feature is supported or not, but even then this exception may be thrown for other - * features. - */ - public static class UnsupportedPosixFeatureException extends PosixException { - - private static final long serialVersionUID = 1846254827094902593L; - - public UnsupportedPosixFeatureException(String message) { - super(message); - } - } - - /** - * Simple wrapper that allows exchanging byte buffers with the outside world. - */ - @ValueType - public static class Buffer { - public final byte[] data; - public long length; - - public Buffer(byte[] data, long length) { - assert data != null && length >= 0 && length <= data.length; - this.data = data; - this.length = length; - } - - public static Buffer allocate(long capacity) { - if (capacity > Integer.MAX_VALUE) { - throw CompilerDirectives.shouldNotReachHere("Long arrays are not supported yet"); - } - return new Buffer(new byte[(int) capacity], 0); - } - - public static Buffer wrap(byte[] data) { - return new Buffer(data, data.length); - } - - public Buffer withLength(long newLength) { - if (newLength > data.length) { - throw CompilerDirectives.shouldNotReachHere("Actual length cannot be greater than capacity"); - } - length = newLength; - return this; - } - - @TruffleBoundary - public ByteBuffer getByteBuffer() { - return ByteBuffer.wrap(data, 0, (int) length); - } - } - - /** - * Corresponds to the {@code timeval} struct. - */ - @ValueType - public static final class Timeval { - public static final Timeval SELECT_TIMEOUT_NOW = new Timeval(0, 0); - - private final long seconds; - private final long microseconds; - - public Timeval(long seconds, long microseconds) { - this.seconds = seconds; - this.microseconds = microseconds; - } - - public long getSeconds() { - return seconds; - } - - public long getMicroseconds() { - return microseconds; - } - } - - /** - * Wraps boolean arrays that indicate if given file descriptor was selected or not. For example, - * if {@code getReadFds()[X]} is {@code true}, then the file descriptor that was passed to - * {@code select} as {@code readfds[X]} was selected. - */ - @ValueType - public static final class SelectResult { - private final boolean[] readfds; - private final boolean[] writefds; - private final boolean[] errorfds; - - public SelectResult(boolean[] readfds, boolean[] writefds, boolean[] errorfds) { - this.readfds = readfds; - this.writefds = writefds; - this.errorfds = errorfds; - } - - public boolean[] getReadFds() { - return readfds; - } - - public boolean[] getWriteFds() { - return writefds; - } - - public boolean[] getErrorFds() { - return errorfds; - } - - @Override - public String toString() { - CompilerAsserts.neverPartOfCompilation(); - return String.format("select[read = %s; write = %s; err = %s]", Arrays.toString(readfds), Arrays.toString(writefds), Arrays.toString(errorfds)); - } - } - - // from stat.h macros - private static boolean istype(long mode, int mask) { - return (mode & S_IFMT.value) == mask; - } - - public static boolean isDIR(long mode) { - return istype(mode, S_IFDIR.value); - } - - public static boolean isCHR(long mode) { - return istype(mode, S_IFCHR.value); - } - - public static boolean isBLK(long mode) { - return istype(mode, S_IFBLK.value); - } - - public static boolean isREG(long mode) { - return istype(mode, S_IFREG.value); - } - - public static boolean isFIFO(long mode) { - return istype(mode, S_IFIFO.value); - } - - public static boolean isLNK(long mode) { - return istype(mode, S_IFLNK.value); - } - - public static class ChannelNotSelectableException extends UnsupportedPosixFeatureException { - private static final long serialVersionUID = -4185480181939639297L; - static ChannelNotSelectableException INSTANCE = new ChannelNotSelectableException(); - - private ChannelNotSelectableException() { - super(null); - } - } - - static final LibraryFactory FACTORY = LibraryFactory.resolve(PosixSupportLibrary.class); - - public static LibraryFactory getFactory() { - return FACTORY; - } - - public static PosixSupportLibrary getUncached() { - return FACTORY.getUncached(); - } -} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java index eff964a8bd..993e875763 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java @@ -45,42 +45,20 @@ import java.util.HashSet; import java.util.IdentityHashMap; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AcceptResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.AddrInfoCursor; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Buffer; -import com.oracle.graal.python.runtime.PosixSupportLibrary.GetAddrInfoException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet4SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Inet6SockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidAddressException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.InvalidUnixSocketPathException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.OpenPtyResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.PwdResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RecvfromResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.RusageResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.SelectResult; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UniversalSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnixSockAddr; -import com.oracle.graal.python.runtime.PosixSupportLibrary.UnsupportedPosixFeatureException; -import com.oracle.graal.python.runtime.PosixSupportLibrary.WindowsVersion; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLanguage.Env; -import com.oracle.truffle.api.library.CachedLibrary; -import com.oracle.truffle.api.library.ExportLibrary; -import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; -@ExportLibrary(PosixSupportLibrary.class) -public class PreInitPosixSupport extends PosixSupport { +public final class PreInitPosixSupport extends PosixSupport { - protected final PosixSupport nativePosixSupport; - private PosixSupport emulatedPosixSupport; + private final NativePosixSupport nativePosixSupport; + private EmulatedPosixSupport emulatedPosixSupport; private HashSet emulatedFds; private IdentityHashMap emulatedDirStreams; private boolean inPreInitialization; - public PreInitPosixSupport(Env env, PosixSupport nativePosixSupport, PosixSupport emulatedPosixSupport) { + public PreInitPosixSupport(Env env, NativePosixSupport nativePosixSupport, EmulatedPosixSupport emulatedPosixSupport) { this.inPreInitialization = env.isPreInitialization(); this.nativePosixSupport = nativePosixSupport; this.emulatedPosixSupport = emulatedPosixSupport; @@ -90,6 +68,11 @@ public PreInitPosixSupport(Env env, PosixSupport nativePosixSupport, PosixSuppor } } + /** Returns the backend appropriate for the current execution phase. */ + public PosixSupport getCurrentBackend() { + return inPreInitialization && emulatedPosixSupport != null ? emulatedPosixSupport : nativePosixSupport; + } + @Override public void setEnv(Env env) { assert !env.isPreInitialization(); @@ -152,1142 +135,1101 @@ private Object removeDirStream(Object dirStream) { return dirStream; } - @ExportMessage - final TruffleString getBackend(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final TruffleString getBackend() { checkNotInPreInitialization(); - return nativeLib.getBackend(nativePosixSupport); + return nativePosixSupport.getBackend(); } - @ExportMessage - final TruffleString strerror(int errorCode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final TruffleString strerror(int errorCode) { checkNotInPreInitialization(); - return nativeLib.strerror(nativePosixSupport, errorCode); + return nativePosixSupport.strerror(errorCode); } - @ExportMessage - final long getpid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final long getpid() { checkNotInPreInitialization(); - return nativeLib.getpid(nativePosixSupport); + return nativePosixSupport.getpid(); } - @ExportMessage - final int umask(int mask, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int umask(int mask) throws PosixException { checkNotInPreInitialization(); - return nativeLib.umask(nativePosixSupport, mask); + return nativePosixSupport.umask(mask); + } + + @Override + @TruffleBoundary + public final int openat(int dirFd, Object pathname, int flags, int mode) throws PosixException { + if (inPreInitialization) { + return addFd(emulatedPosixSupport.openat(dirFd, pathname, flags, mode)); + } + return nativePosixSupport.openat(dirFd, pathname, flags, mode); } - @ExportMessage - final int openat(int dirFd, Object pathname, int flags, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int close(int fd) throws PosixException { if (inPreInitialization) { - return addFd(PosixSupportLibrary.getUncached().openat(emulatedPosixSupport, dirFd, pathname, flags, mode)); + return emulatedPosixSupport.close(removeFd(fd)); } - return nativeLib.openat(nativePosixSupport, dirFd, pathname, flags, mode); + return nativePosixSupport.close(fd); } - @ExportMessage - final int close(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Buffer read(int fd, long length) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().close(emulatedPosixSupport, removeFd(fd)); + return emulatedPosixSupport.read(fd, length); } - return nativeLib.close(nativePosixSupport, fd); + return nativePosixSupport.read(fd, length); + } + + @Override + @TruffleBoundary + public final long write(int fd, Buffer data) throws PosixException { + checkNotInPreInitialization(); + return nativePosixSupport.write(fd, data); } - @ExportMessage - final Buffer read(int fd, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int getWindowsConsoleType(int fd) { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().read(emulatedPosixSupport, fd, length); + return 0; } - return nativeLib.read(nativePosixSupport, fd, length); + return nativePosixSupport.getWindowsConsoleType(fd); } - @ExportMessage - final long write(int fd, Buffer data, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long writeWindowsConsole(int fd, Buffer data) throws PosixException { checkNotInPreInitialization(); - return nativeLib.write(nativePosixSupport, fd, data); + return nativePosixSupport.writeWindowsConsole(fd, data); } - @ExportMessage - final int dup(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int dup(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dup(nativePosixSupport, fd); + return nativePosixSupport.dup(fd); } - @ExportMessage - final int dup2(int fd, int fd2, boolean inheritable, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int dup2(int fd, int fd2, boolean inheritable) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dup2(nativePosixSupport, fd, fd2, inheritable); + return nativePosixSupport.dup2(fd, fd2, inheritable); } - @ExportMessage - final boolean getInheritable(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final boolean getInheritable(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getInheritable(nativePosixSupport, fd); + return nativePosixSupport.getInheritable(fd); } - @ExportMessage - final void setInheritable(int fd, boolean inheritable, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setInheritable(int fd, boolean inheritable) throws PosixException { if (inPreInitialization) { - PosixSupportLibrary.getUncached().setInheritable(emulatedPosixSupport, fd, inheritable); + emulatedPosixSupport.setInheritable(fd, inheritable); return; } - nativeLib.setInheritable(nativePosixSupport, fd, inheritable); + nativePosixSupport.setInheritable(fd, inheritable); } - @ExportMessage - final long getOsfHandle(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long getOsfHandle(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getOsfHandle(nativePosixSupport, fd); + return nativePosixSupport.getOsfHandle(fd); } - @ExportMessage - final int openOsfHandle(long handle, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int openOsfHandle(long handle, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.openOsfHandle(nativePosixSupport, handle, flags); + return nativePosixSupport.openOsfHandle(handle, flags); } - @ExportMessage - final int setMode(int fd, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int setMode(int fd, int mode) throws PosixException { checkNotInPreInitialization(); - return nativeLib.setMode(nativePosixSupport, fd, mode); + return nativePosixSupport.setMode(fd, mode); } - @ExportMessage - final void msvcrtLocking(int fd, int mode, long nbytes, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void msvcrtLocking(int fd, int mode, long nbytes) throws PosixException { checkNotInPreInitialization(); - nativeLib.msvcrtLocking(nativePosixSupport, fd, mode, nbytes); + nativePosixSupport.msvcrtLocking(fd, mode, nbytes); } - @ExportMessage - final int[] pipe(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int[] pipe() throws PosixException { checkNotInPreInitialization(); - return nativeLib.pipe(nativePosixSupport); + return nativePosixSupport.pipe(); } - @ExportMessage - final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final SelectResult select(int[] readfds, int[] writefds, int[] errorfds, Timeval timeout) throws PosixException { checkNotInPreInitialization(); - return nativeLib.select(nativePosixSupport, readfds, writefds, errorfds, timeout); + return nativePosixSupport.select(readfds, writefds, errorfds, timeout); } - @ExportMessage - final void poll(int[] fds, int[] events, int[] revents, int timeout, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void poll(int[] fds, int[] events, int[] revents, int timeout) throws PosixException { checkNotInPreInitialization(); - nativeLib.poll(nativePosixSupport, fds, events, revents, timeout); + nativePosixSupport.poll(fds, events, revents, timeout); } - @ExportMessage - final long lseek(int fd, long offset, int how, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long lseek(int fd, long offset, int how) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().lseek(emulatedPosixSupport, fd, offset, how); + return emulatedPosixSupport.lseek(fd, offset, how); } - return nativeLib.lseek(nativePosixSupport, fd, offset, how); + return nativePosixSupport.lseek(fd, offset, how); } - @ExportMessage - final void ftruncate(int fd, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void ftruncate(int fd, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.ftruncate(nativePosixSupport, fd, length); + nativePosixSupport.ftruncate(fd, length); } - @ExportMessage - final void truncate(Object path, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void truncate(Object path, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.truncate(nativePosixSupport, path, length); + nativePosixSupport.truncate(path, length); } - @ExportMessage - final void fsync(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fsync(int fd) throws PosixException { checkNotInPreInitialization(); - nativeLib.fsync(nativePosixSupport, fd); + nativePosixSupport.fsync(fd); } - @ExportMessage - final void flock(int fd, int operation, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void flock(int fd, int operation) throws PosixException { checkNotInPreInitialization(); - nativeLib.flock(nativePosixSupport, fd, operation); + nativePosixSupport.flock(fd, operation); } - @ExportMessage - final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fcntlLock(int fd, boolean blocking, int lockType, int whence, long start, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.fcntlLock(nativePosixSupport, fd, blocking, lockType, whence, start, length); + nativePosixSupport.fcntlLock(fd, blocking, lockType, whence, start, length); } - @ExportMessage - final boolean getBlocking(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final boolean getBlocking(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getBlocking(nativePosixSupport, fd); + return nativePosixSupport.getBlocking(fd); } - @ExportMessage - final void setBlocking(int fd, boolean blocking, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setBlocking(int fd, boolean blocking) throws PosixException { checkNotInPreInitialization(); - nativeLib.setBlocking(nativePosixSupport, fd, blocking); + nativePosixSupport.setBlocking(fd, blocking); } - @ExportMessage - final int[] getTerminalSize(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int[] getTerminalSize(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getTerminalSize(nativePosixSupport, fd); + return nativePosixSupport.getTerminalSize(fd); } - @ExportMessage - final long sysconf(int name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long sysconf(int name) throws PosixException { checkNotInPreInitialization(); - return nativeLib.sysconf(nativePosixSupport, name); + return nativePosixSupport.sysconf(name); } - @ExportMessage - final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatat(int dirFd, Object pathname, boolean followSymlinks) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstatat(emulatedPosixSupport, dirFd, pathname, followSymlinks); + return emulatedPosixSupport.fstatat(dirFd, pathname, followSymlinks); } - return nativeLib.fstatat(nativePosixSupport, dirFd, pathname, followSymlinks); + return nativePosixSupport.fstatat(dirFd, pathname, followSymlinks); } - @ExportMessage - final long[] fstat(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstat(int fd) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstat(emulatedPosixSupport, fd); + return emulatedPosixSupport.fstat(fd); } - return nativeLib.fstat(nativePosixSupport, fd); + return nativePosixSupport.fstat(fd); } - @ExportMessage - final long[] statvfs(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] statvfs(Object path) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().statvfs(emulatedPosixSupport, path); + return emulatedPosixSupport.statvfs(path); } - return nativeLib.statvfs(nativePosixSupport, path); + return nativePosixSupport.statvfs(path); } - @ExportMessage - final long[] fstatvfs(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] fstatvfs(int fd) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().fstatvfs(emulatedPosixSupport, fd); + return emulatedPosixSupport.fstatvfs(fd); } - return nativeLib.fstatvfs(nativePosixSupport, fd); + return nativePosixSupport.fstatvfs(fd); } - @ExportMessage - final Object[] uname(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object[] uname() throws PosixException { checkNotInPreInitialization(); - return nativeLib.uname(nativePosixSupport); + return nativePosixSupport.uname(); } - @ExportMessage - final WindowsVersion getWindowsVersion(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final WindowsVersion getWindowsVersion() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getWindowsVersion(nativePosixSupport); + return nativePosixSupport.getWindowsVersion(); } - @ExportMessage - final void unlinkat(int dirFd, Object pathname, boolean rmdir, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void unlinkat(int dirFd, Object pathname, boolean rmdir) throws PosixException { checkNotInPreInitialization(); - nativeLib.unlinkat(nativePosixSupport, dirFd, pathname, rmdir); + nativePosixSupport.unlinkat(dirFd, pathname, rmdir); } - @ExportMessage - final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void linkat(int oldFdDir, Object oldPath, int newFdDir, Object newPath, int flags) throws PosixException { checkNotInPreInitialization(); - nativeLib.linkat(nativePosixSupport, oldFdDir, oldPath, newFdDir, newPath, flags); + nativePosixSupport.linkat(oldFdDir, oldPath, newFdDir, newPath, flags); } - @ExportMessage - final void symlinkat(Object target, int linkpathDirFd, Object linkpath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void symlinkat(Object target, int linkpathDirFd, Object linkpath) throws PosixException { checkNotInPreInitialization(); - nativeLib.symlinkat(nativePosixSupport, target, linkpathDirFd, linkpath); + nativePosixSupport.symlinkat(target, linkpathDirFd, linkpath); } - @ExportMessage - final void mkdirat(int dirFd, Object pathname, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mkdirat(int dirFd, Object pathname, int mode) throws PosixException { checkNotInPreInitialization(); - nativeLib.mkdirat(nativePosixSupport, dirFd, pathname, mode); + nativePosixSupport.mkdirat(dirFd, pathname, mode); } - @ExportMessage - final Object getcwd(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object getcwd() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getcwd(nativePosixSupport); + return nativePosixSupport.getcwd(); } - @ExportMessage - final void chdir(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void chdir(Object path) throws PosixException { checkNotInPreInitialization(); - nativeLib.chdir(nativePosixSupport, path); + nativePosixSupport.chdir(path); } - @ExportMessage - final void fchdir(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchdir(int fd) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchdir(nativePosixSupport, fd); + nativePosixSupport.fchdir(fd); } - @ExportMessage - final boolean isatty(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean isatty(int fd) { checkNotInPreInitialization(); - return nativeLib.isatty(nativePosixSupport, fd); + return nativePosixSupport.isatty(fd); } - @ExportMessage - final Object opendir(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object opendir(Object path) throws PosixException { if (inPreInitialization) { - return addDirStream(PosixSupportLibrary.getUncached().opendir(emulatedPosixSupport, path)); + return addDirStream(emulatedPosixSupport.opendir(path)); } - return nativeLib.opendir(nativePosixSupport, path); + return nativePosixSupport.opendir(path); } - @ExportMessage - final Object fdopendir(int fd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object fdopendir(int fd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.fdopendir(nativePosixSupport, fd); + return nativePosixSupport.fdopendir(fd); } - @ExportMessage - final void closedir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void closedir(Object dirStream) throws PosixException { if (inPreInitialization) { - PosixSupportLibrary.getUncached().closedir(emulatedPosixSupport, removeDirStream(dirStream)); + emulatedPosixSupport.closedir(removeDirStream(dirStream)); return; } - nativeLib.closedir(nativePosixSupport, dirStream); + nativePosixSupport.closedir(dirStream); } - @ExportMessage - final Object readdir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object readdir(Object dirStream) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().readdir(emulatedPosixSupport, dirStream); + return emulatedPosixSupport.readdir(dirStream); } - return nativeLib.readdir(nativePosixSupport, dirStream); + return nativePosixSupport.readdir(dirStream); } - @ExportMessage - final void rewinddir(Object dirStream, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final void rewinddir(Object dirStream) { if (inPreInitialization) { - PosixSupportLibrary.getUncached().rewinddir(emulatedPosixSupport, dirStream); + emulatedPosixSupport.rewinddir(dirStream); + return; } - nativeLib.rewinddir(nativePosixSupport, dirStream); + nativePosixSupport.rewinddir(dirStream); } - @ExportMessage - final Object dirEntryGetName(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetName(Object dirEntry) throws PosixException { if (inPreInitialization) { - return PosixSupportLibrary.getUncached().dirEntryGetName(emulatedPosixSupport, dirEntry); + return emulatedPosixSupport.dirEntryGetName(dirEntry); } - return nativeLib.dirEntryGetName(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetName(dirEntry); } - @ExportMessage - final Object dirEntryGetPath(Object dirEntry, Object scandirPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object dirEntryGetPath(Object dirEntry, Object scandirPath) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dirEntryGetPath(nativePosixSupport, dirEntry, scandirPath); + return nativePosixSupport.dirEntryGetPath(dirEntry, scandirPath); } - @ExportMessage - final long dirEntryGetInode(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long dirEntryGetInode(Object dirEntry) throws PosixException { checkNotInPreInitialization(); - return nativeLib.dirEntryGetInode(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetInode(dirEntry); } - @ExportMessage - final int dirEntryGetType(Object dirEntry, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int dirEntryGetType(Object dirEntry) { checkNotInPreInitialization(); - return nativeLib.dirEntryGetType(nativePosixSupport, dirEntry); + return nativePosixSupport.dirEntryGetType(dirEntry); } - @ExportMessage - final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void utimensat(int dirFd, Object pathname, long[] timespec, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.utimensat(nativePosixSupport, dirFd, pathname, timespec, followSymlinks); + nativePosixSupport.utimensat(dirFd, pathname, timespec, followSymlinks); } - @ExportMessage - final void futimens(int fd, long[] timespec, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void futimens(int fd, long[] timespec) throws PosixException { checkNotInPreInitialization(); - nativeLib.futimens(nativePosixSupport, fd, timespec); + nativePosixSupport.futimens(fd, timespec); } - @ExportMessage - final void futimes(int fd, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void futimes(int fd, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.futimes(nativePosixSupport, fd, timeval); + nativePosixSupport.futimes(fd, timeval); } - @ExportMessage - final void lutimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void lutimes(Object filename, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.lutimes(nativePosixSupport, filename, timeval); + nativePosixSupport.lutimes(filename, timeval); } - @ExportMessage - final void utimes(Object filename, Timeval[] timeval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void utimes(Object filename, Timeval[] timeval) throws PosixException { checkNotInPreInitialization(); - nativeLib.utimes(nativePosixSupport, filename, timeval); + nativePosixSupport.utimes(filename, timeval); } - @ExportMessage - final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void renameat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { checkNotInPreInitialization(); - nativeLib.renameat(nativePosixSupport, oldDirFd, oldPath, newDirFd, newPath); + nativePosixSupport.renameat(oldDirFd, oldPath, newDirFd, newPath); } - @ExportMessage - final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void replaceat(int oldDirFd, Object oldPath, int newDirFd, Object newPath) throws PosixException { checkNotInPreInitialization(); - nativeLib.replaceat(nativePosixSupport, oldDirFd, oldPath, newDirFd, newPath); + nativePosixSupport.replaceat(oldDirFd, oldPath, newDirFd, newPath); } - @ExportMessage - final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final boolean faccessat(int dirFd, Object path, int mode, boolean effectiveIds, boolean followSymlinks) throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.faccessat(nativePosixSupport, dirFd, path, mode, effectiveIds, followSymlinks); + return nativePosixSupport.faccessat(dirFd, path, mode, effectiveIds, followSymlinks); } - @ExportMessage - final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmodat(int dirFd, Object path, int mode, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchmodat(nativePosixSupport, dirFd, path, mode, followSymlinks); + nativePosixSupport.fchmodat(dirFd, path, mode, followSymlinks); } - @ExportMessage - final void fchmod(int fd, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchmod(int fd, int mode) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchmod(nativePosixSupport, fd, mode); + nativePosixSupport.fchmod(fd, mode); } - @ExportMessage - final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchownat(int dirFd, Object path, long owner, long group, boolean followSymlinks) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchownat(nativePosixSupport, dirFd, path, owner, group, followSymlinks); + nativePosixSupport.fchownat(dirFd, path, owner, group, followSymlinks); } - @ExportMessage - final void fchown(int fd, long owner, long group, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void fchown(int fd, long owner, long group) throws PosixException { checkNotInPreInitialization(); - nativeLib.fchown(nativePosixSupport, fd, owner, group); + nativePosixSupport.fchown(fd, owner, group); } - @ExportMessage - final Object readlinkat(int dirFd, Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object readlinkat(int dirFd, Object path) throws PosixException { checkNotInPreInitialization(); - return nativeLib.readlinkat(nativePosixSupport, dirFd, path); + return nativePosixSupport.readlinkat(dirFd, path); } - @ExportMessage - final void raise(int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void raise(int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.raise(nativePosixSupport, signal); + nativePosixSupport.raise(signal); } - @ExportMessage - final int alarm(int seconds, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int alarm(int seconds) throws PosixException { checkNotInPreInitialization(); - return nativeLib.alarm(nativePosixSupport, seconds); + return nativePosixSupport.alarm(seconds); } - @ExportMessage - final Timeval[] getitimer(int which, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] getitimer(int which) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getitimer(nativePosixSupport, which); + return nativePosixSupport.getitimer(which); } - @ExportMessage - final Timeval[] setitimer(int which, Timeval delay, Timeval interval, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Timeval[] setitimer(int which, Timeval delay, Timeval interval) throws PosixException { checkNotInPreInitialization(); - return nativeLib.setitimer(nativePosixSupport, which, delay, interval); + return nativePosixSupport.setitimer(which, delay, interval); } - @ExportMessage - final void signalSelf(int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void signalSelf(int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.signalSelf(nativePosixSupport, signal); + nativePosixSupport.signalSelf(signal); } - @ExportMessage - final void kill(long pid, int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void kill(long pid, int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.kill(nativePosixSupport, pid, signal); + nativePosixSupport.kill(pid, signal); } - @ExportMessage - final void killpg(long pgid, int signal, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void killpg(long pgid, int signal) throws PosixException { checkNotInPreInitialization(); - nativeLib.killpg(nativePosixSupport, pgid, signal); + nativePosixSupport.killpg(pgid, signal); } - @ExportMessage - final long[] waitpid(long pid, int options, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] waitpid(Node location, long pid, int options) throws PosixException { checkNotInPreInitialization(); - return nativeLib.waitpid(nativePosixSupport, pid, options); + return nativePosixSupport.waitpid(location, pid, options); } - @ExportMessage - final boolean wcoredump(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wcoredump(int status) { checkNotInPreInitialization(); - return nativeLib.wcoredump(nativePosixSupport, status); + return nativePosixSupport.wcoredump(status); } - @ExportMessage - final boolean wifcontinued(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifcontinued(int status) { checkNotInPreInitialization(); - return nativeLib.wifcontinued(nativePosixSupport, status); + return nativePosixSupport.wifcontinued(status); } - @ExportMessage - final boolean wifstopped(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifstopped(int status) { checkNotInPreInitialization(); - return nativeLib.wifstopped(nativePosixSupport, status); + return nativePosixSupport.wifstopped(status); } - @ExportMessage - final boolean wifsignaled(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifsignaled(int status) { checkNotInPreInitialization(); - return nativeLib.wifsignaled(nativePosixSupport, status); + return nativePosixSupport.wifsignaled(status); } - @ExportMessage - final boolean wifexited(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final boolean wifexited(int status) { checkNotInPreInitialization(); - return nativeLib.wifexited(nativePosixSupport, status); + return nativePosixSupport.wifexited(status); } - @ExportMessage - final int wexitstatus(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wexitstatus(int status) { checkNotInPreInitialization(); - return nativeLib.wexitstatus(nativePosixSupport, status); + return nativePosixSupport.wexitstatus(status); } - @ExportMessage - final int wtermsig(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wtermsig(int status) { checkNotInPreInitialization(); - return nativeLib.wtermsig(nativePosixSupport, status); + return nativePosixSupport.wtermsig(status); } - @ExportMessage - final int wstopsig(int status, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int wstopsig(int status) { checkNotInPreInitialization(); - return nativeLib.wstopsig(nativePosixSupport, status); + return nativePosixSupport.wstopsig(status); } - @ExportMessage - final long getuid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final long getuid() { checkNotInPreInitialization(); - return nativeLib.getuid(nativePosixSupport); + return nativePosixSupport.getuid(); } - @ExportMessage - final long geteuid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long geteuid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.geteuid(nativePosixSupport); + return nativePosixSupport.geteuid(); } - @ExportMessage - final long getgid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final long getgid() { checkNotInPreInitialization(); - return nativeLib.getgid(nativePosixSupport); + return nativePosixSupport.getgid(); } - @ExportMessage - final long getegid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getegid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getegid(nativePosixSupport); + return nativePosixSupport.getegid(); } - @ExportMessage - final long getppid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getppid() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getppid(nativePosixSupport); + return nativePosixSupport.getppid(); } - @ExportMessage - final long getpgid(long pid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long getpgid(long pid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpgid(nativePosixSupport, pid); + return nativePosixSupport.getpgid(pid); } - @ExportMessage - final void setpgid(long pid, long pgid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setpgid(long pid, long pgid) throws PosixException { checkNotInPreInitialization(); - nativeLib.setpgid(nativePosixSupport, pid, pgid); + nativePosixSupport.setpgid(pid, pgid); } - @ExportMessage - final long getpgrp(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long getpgrp() throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.getpgrp(nativePosixSupport); + return nativePosixSupport.getpgrp(); } - @ExportMessage - final long getsid(long pid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long getsid(long pid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsid(nativePosixSupport, pid); + return nativePosixSupport.getsid(pid); } - @ExportMessage - final long setsid( - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long setsid() throws PosixException { checkNotInPreInitialization(); - return nativeLib.setsid(nativePosixSupport); + return nativePosixSupport.setsid(); } - @ExportMessage - final long[] getgroups( - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final long[] getgroups() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getgroups(nativePosixSupport); + return nativePosixSupport.getgroups(); } - @ExportMessage - final RusageResult getrusage(int who, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final RusageResult getrusage(int who) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getrusage(nativePosixSupport, who); + return nativePosixSupport.getrusage(who); } - @ExportMessage - final OpenPtyResult openpty(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final OpenPtyResult openpty() throws PosixException { checkNotInPreInitialization(); - return nativeLib.openpty(nativePosixSupport); + return nativePosixSupport.openpty(); } - @ExportMessage - final TruffleString ctermid(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object ctermid() throws PosixException { checkNotInPreInitialization(); - return nativeLib.ctermid(nativePosixSupport); + return nativePosixSupport.ctermid(); } - @ExportMessage - final void setenv(Object name, Object value, boolean overwrite, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setenv(Object name, Object value, boolean overwrite) throws PosixException { checkNotInPreInitialization(); - nativeLib.setenv(nativePosixSupport, name, value, overwrite); + nativePosixSupport.setenv(name, value, overwrite); } - @ExportMessage - final void unsetenv(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void unsetenv(Object name) throws PosixException { checkNotInPreInitialization(); - nativeLib.unsetenv(nativePosixSupport, name); + nativePosixSupport.unsetenv(name); } - @ExportMessage - final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, int stderrWriteFd, - int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int forkExec(Object[] executables, Object[] args, Object cwd, Object[] env, int stdinReadFd, int stdinWriteFd, int stdoutReadFd, int stdoutWriteFd, int stderrReadFd, + int stderrWriteFd, + int errPipeReadFd, int errPipeWriteFd, boolean closeFds, boolean restoreSignals, boolean callSetsid, int pgidToSet, int[] fdsToKeep, boolean allowVFork) throws PosixException { checkNotInPreInitialization(); - return nativeLib.forkExec(nativePosixSupport, executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, + return nativePosixSupport.forkExec(executables, args, cwd, env, stdinReadFd, stdinWriteFd, stdoutReadFd, stdoutWriteFd, stderrReadFd, stderrWriteFd, errPipeReadFd, errPipeWriteFd, closeFds, restoreSignals, callSetsid, pgidToSet, fdsToKeep, allowVFork); } - @ExportMessage - final void execv(Object pathname, Object[] args, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void execv(Object pathname, Object[] args) throws PosixException { checkNotInPreInitialization(); - nativeLib.execv(nativePosixSupport, pathname, args); + nativePosixSupport.execv(pathname, args); } - @ExportMessage - final int system(Object command, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int system(Object command) { checkNotInPreInitialization(); - return nativeLib.system(nativePosixSupport, command); + return nativePosixSupport.system(command); } - @ExportMessage - final Object mmap(long length, int prot, int flags, int fd, long offset, Object tagname, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object mmap(Node location, long length, int prot, int flags, int fd, long offset, Object tagname) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmap(nativePosixSupport, length, prot, flags, fd, offset, tagname); + return nativePosixSupport.mmap(location, length, prot, flags, fd, offset, tagname); } - @ExportMessage - final byte mmapReadByte(Object mmap, long index, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final byte mmapReadByte(Object mmap, long index) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmapReadByte(nativePosixSupport, mmap, index); + return nativePosixSupport.mmapReadByte(mmap, index); } - @ExportMessage - final void mmapWriteByte(Object mmap, long index, byte value, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapWriteByte(Object mmap, long index, byte value) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapWriteByte(nativePosixSupport, mmap, index, value); + nativePosixSupport.mmapWriteByte(mmap, index, value); } - @ExportMessage - final int mmapReadBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int mmapReadBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { checkNotInPreInitialization(); - return nativeLib.mmapReadBytes(nativePosixSupport, mmap, index, bytes, length); + return nativePosixSupport.mmapReadBytes(mmap, index, bytes, length); } - @ExportMessage - final void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapWriteBytes(Object mmap, long index, byte[] bytes, int length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapWriteBytes(nativePosixSupport, mmap, index, bytes, length); + nativePosixSupport.mmapWriteBytes(mmap, index, bytes, length); } - @ExportMessage - final void mmapFlush(Object mmap, long offset, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapFlush(Object mmap, long offset, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapFlush(nativePosixSupport, mmap, offset, length); + nativePosixSupport.mmapFlush(mmap, offset, length); } - @ExportMessage - final void mmapUnmap(Object mmap, long length, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void mmapUnmap(Object mmap, long length) throws PosixException { checkNotInPreInitialization(); - nativeLib.mmapUnmap(nativePosixSupport, mmap, length); + nativePosixSupport.mmapUnmap(mmap, length); } - @ExportMessage - @SuppressWarnings("static-method") - final long mmapGetPointer(Object mmap, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException { + @Override + @TruffleBoundary + public final long mmapGetPointer(Object mmap) throws UnsupportedPosixFeatureException { checkNotInPreInitialization(); - return nativeLib.mmapGetPointer(nativePosixSupport, mmap); + return nativePosixSupport.mmapGetPointer(mmap); } - @ExportMessage - public PwdResult getpwuid(long uid, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwuid(long uid) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwuid(nativePosixSupport, uid); + return nativePosixSupport.getpwuid(uid); } - @ExportMessage - public PwdResult getpwnam(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult getpwnam(Object name) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwnam(nativePosixSupport, name); + return nativePosixSupport.getpwnam(name); } - @ExportMessage - public boolean hasGetpwentries(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - return nativeLib.hasGetpwentries(nativePosixSupport); + @Override + @TruffleBoundary + public boolean hasGetpwentries() { + return nativePosixSupport.hasGetpwentries(); } - @ExportMessage - public PwdResult[] getpwentries(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public PwdResult[] getpwentries() throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpwentries(nativePosixSupport); + return nativePosixSupport.getpwentries(); } - @ExportMessage - final int ioctlBytes(int fd, long request, byte[] arg, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlBytes(int fd, long request, byte[] arg) throws PosixException { checkNotInPreInitialization(); - return nativeLib.ioctlBytes(nativePosixSupport, fd, request, arg); + return nativePosixSupport.ioctlBytes(fd, request, arg); } - @ExportMessage - final int ioctlInt(int fd, long request, int arg, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int ioctlInt(int fd, long request, int arg) throws PosixException { checkNotInPreInitialization(); - return nativeLib.ioctlInt(nativePosixSupport, fd, request, arg); + return nativePosixSupport.ioctlInt(fd, request, arg); } - @ExportMessage - final int socket(int domain, int type, int protocol, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int socket(int domain, int type, int protocol) throws PosixException { checkNotInPreInitialization(); - return nativeLib.socket(nativePosixSupport, domain, type, protocol); + return nativePosixSupport.socket(domain, type, protocol); } - @ExportMessage - final AcceptResult accept(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final AcceptResult accept(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.accept(nativePosixSupport, sockfd); + return nativePosixSupport.accept(sockfd); } - @ExportMessage - final void bind(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void bind(int sockfd, UniversalSockAddr addr) throws PosixException { checkNotInPreInitialization(); - nativeLib.bind(nativePosixSupport, sockfd, addr); + nativePosixSupport.bind(sockfd, addr); } - @ExportMessage - final void connect(int sockfd, UniversalSockAddr addr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void connect(int sockfd, UniversalSockAddr addr) throws PosixException { checkNotInPreInitialization(); - nativeLib.connect(nativePosixSupport, sockfd, addr); + nativePosixSupport.connect(sockfd, addr); } - @ExportMessage - final void listen(int sockfd, int backlog, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void listen(int sockfd, int backlog) throws PosixException { checkNotInPreInitialization(); - nativeLib.listen(nativePosixSupport, sockfd, backlog); + nativePosixSupport.listen(sockfd, backlog); } - @ExportMessage - final UniversalSockAddr getpeername(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getpeername(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getpeername(nativePosixSupport, sockfd); + return nativePosixSupport.getpeername(sockfd); } - @ExportMessage - final UniversalSockAddr getsockname(int sockfd, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final UniversalSockAddr getsockname(int sockfd) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsockname(nativePosixSupport, sockfd); + return nativePosixSupport.getsockname(sockfd); } - @ExportMessage - final int send(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int send(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.send(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.send(sockfd, buf, offset, len, flags); } - @ExportMessage - final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int sendto(int sockfd, byte[] buf, int offset, int len, int flags, UniversalSockAddr destAddr) throws PosixException { checkNotInPreInitialization(); - return nativeLib.sendto(nativePosixSupport, sockfd, buf, offset, len, flags, destAddr); + return nativePosixSupport.sendto(sockfd, buf, offset, len, flags, destAddr); } - @ExportMessage - final int recv(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int recv(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.recv(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.recv(sockfd, buf, offset, len, flags); } - @ExportMessage - final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final RecvfromResult recvfrom(int sockfd, byte[] buf, int offset, int len, int flags) throws PosixException { checkNotInPreInitialization(); - return nativeLib.recvfrom(nativePosixSupport, sockfd, buf, offset, len, flags); + return nativePosixSupport.recvfrom(sockfd, buf, offset, len, flags); } - @ExportMessage - final void shutdown(int sockfd, int how, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void shutdown(int sockfd, int how) throws PosixException { checkNotInPreInitialization(); - nativeLib.shutdown(nativePosixSupport, sockfd, how); + nativePosixSupport.shutdown(sockfd, how); } - @ExportMessage - final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final int getsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { checkNotInPreInitialization(); - return nativeLib.getsockopt(nativePosixSupport, sockfd, level, optname, optval, optlen); + return nativePosixSupport.getsockopt(sockfd, level, optname, optval, optlen); } - @ExportMessage - final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final void setsockopt(int sockfd, int level, int optname, byte[] optval, int optlen) throws PosixException { checkNotInPreInitialization(); - nativeLib.setsockopt(nativePosixSupport, sockfd, level, optname, optval, optlen); + nativePosixSupport.setsockopt(sockfd, level, optname, optval, optlen); } - @ExportMessage - final int inet_addr(Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final int inet_addr(Object src) { checkNotInPreInitialization(); - return nativeLib.inet_addr(nativePosixSupport, src); + return nativePosixSupport.inet_addr(src); } - @ExportMessage - final int inet_aton(Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws InvalidAddressException { + @Override + @TruffleBoundary + public final int inet_aton(Object src) throws InvalidAddressException { checkNotInPreInitialization(); - return nativeLib.inet_aton(nativePosixSupport, src); + return nativePosixSupport.inet_aton(src); } - @ExportMessage - final Object inet_ntoa(int address, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final Object inet_ntoa(int address) { checkNotInPreInitialization(); - return nativeLib.inet_ntoa(nativePosixSupport, address); + return nativePosixSupport.inet_ntoa(address); } - @ExportMessage - final byte[] inet_pton(int family, Object src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException, InvalidAddressException { + @Override + @TruffleBoundary + public final byte[] inet_pton(int family, Object src) throws PosixException, InvalidAddressException { checkNotInPreInitialization(); - return nativeLib.inet_pton(nativePosixSupport, family, src); + return nativePosixSupport.inet_pton(family, src); } - @ExportMessage - final Object inet_ntop(int family, byte[] src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object inet_ntop(int family, byte[] src) throws PosixException { checkNotInPreInitialization(); - return nativeLib.inet_ntop(nativePosixSupport, family, src); + return nativePosixSupport.inet_ntop(family, src); } - @ExportMessage - final Object gethostname(@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws PosixException { + @Override + @TruffleBoundary + public final Object gethostname() throws PosixException { checkNotInPreInitialization(); - return nativeLib.gethostname(nativePosixSupport); + return nativePosixSupport.gethostname(); } - @ExportMessage - final Object[] getnameinfo(UniversalSockAddr addr, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final Object[] getnameinfo(UniversalSockAddr addr, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { checkNotInPreInitialization(); - return nativeLib.getnameinfo(nativePosixSupport, addr, flags); + return nativePosixSupport.getnameinfo(addr, flags); } - @ExportMessage - final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, GetAddrInfoException { + @Override + @TruffleBoundary + public final AddrInfoCursor getaddrinfo(Object node, Object service, int family, int sockType, int protocol, int flags) throws UnsupportedPosixFeatureException, GetAddrInfoException { checkNotInPreInitialization(); - return nativeLib.getaddrinfo(nativePosixSupport, node, service, family, sockType, protocol, flags); + return nativePosixSupport.getaddrinfo(node, service, family, sockType, protocol, flags); } - @ExportMessage - final long semOpen(Object name, int openFlags, int mode, int value, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final long semOpen(Object name, int openFlags, int mode, int value) throws PosixException { checkNotInPreInitialization(); - return lib.semOpen(nativePosixSupport, name, openFlags, mode, value); + return nativePosixSupport.semOpen(name, openFlags, mode, value); } - @ExportMessage - final void semClose(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semClose(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semClose(nativePosixSupport, handle); + nativePosixSupport.semClose(handle); } - @ExportMessage - final void semUnlink(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semUnlink(Object name) throws PosixException { checkNotInPreInitialization(); - lib.semUnlink(nativePosixSupport, name); + nativePosixSupport.semUnlink(name); } - @ExportMessage - final int shmOpen(Object name, int openFlags, int mode, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int shmOpen(Object name, int openFlags, int mode) throws PosixException { checkNotInPreInitialization(); - return lib.shmOpen(nativePosixSupport, name, openFlags, mode); + return nativePosixSupport.shmOpen(name, openFlags, mode); } - @ExportMessage - final void shmUnlink(Object name, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void shmUnlink(Object name) throws PosixException { checkNotInPreInitialization(); - lib.shmUnlink(nativePosixSupport, name); + nativePosixSupport.shmUnlink(name); } - @ExportMessage - final int semGetValue(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final int semGetValue(long handle) throws PosixException { checkNotInPreInitialization(); - return lib.semGetValue(nativePosixSupport, handle); + return nativePosixSupport.semGetValue(handle); } - @ExportMessage - final void semPost(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semPost(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semPost(nativePosixSupport, handle); + nativePosixSupport.semPost(handle); } - @ExportMessage - final void semWait(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final void semWait(long handle) throws PosixException { checkNotInPreInitialization(); - lib.semWait(nativePosixSupport, handle); + nativePosixSupport.semWait(handle); } - @ExportMessage - final boolean semTryWait(long handle, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTryWait(long handle) throws PosixException { checkNotInPreInitialization(); - return lib.semTryWait(nativePosixSupport, handle); + return nativePosixSupport.semTryWait(handle); } - @ExportMessage - final boolean semTimedWait(long handle, long deadlineNs, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException { + @Override + @TruffleBoundary + public final boolean semTimedWait(Node location, long handle, long deadlineNs) throws PosixException { checkNotInPreInitialization(); - return lib.semTimedWait(nativePosixSupport, handle, deadlineNs); + return nativePosixSupport.semTimedWait(location, handle, deadlineNs); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet4(Inet4SockAddr src) { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrInet4(nativePosixSupport, src); + return nativePosixSupport.createUniversalSockAddrInet4(src); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrInet6(Inet6SockAddr src) { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrInet6(nativePosixSupport, src); + return nativePosixSupport.createUniversalSockAddrInet6(src); } - @ExportMessage - final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { + @Override + @TruffleBoundary + public final UniversalSockAddr createUniversalSockAddrUnix(UnixSockAddr src) throws UnsupportedPosixFeatureException, InvalidUnixSocketPathException { checkNotInPreInitialization(); - return nativeLib.createUniversalSockAddrUnix(nativePosixSupport, src); - } - - @ExportMessage - final Object createPathFromString(TruffleString path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createPathFromString(emulatedPosixSupport, path); - } - return nativeLib.createPathFromString(nativePosixSupport, path); + return nativePosixSupport.createUniversalSockAddrUnix(src); } - @ExportMessage - final Object createPathFromBytes(byte[] path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createPathFromBytes(emulatedPosixSupport, path); - } - return nativeLib.createPathFromBytes(nativePosixSupport, path); - } - - @ExportMessage - final TruffleString getPathAsString(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getPathAsString(emulatedPosixSupport, path); - } - return nativeLib.getPathAsString(nativePosixSupport, path); - } - - @ExportMessage - final Buffer getPathAsBytes(Object path, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getPathAsBytes(emulatedPosixSupport, path); - } - return nativeLib.getPathAsBytes(nativePosixSupport, path); - } - - @ExportMessage - final Object createCStringFromString(TruffleString string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createCStringFromString(emulatedPosixSupport, string); - } - return nativeLib.createCStringFromString(nativePosixSupport, string); - } - - @ExportMessage - final Object createCStringFromBytes(byte[] bytes, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createCStringFromBytes(emulatedPosixSupport, bytes); - } - return nativeLib.createCStringFromBytes(nativePosixSupport, bytes); - } - - @ExportMessage - final Object createWideStringFromString(TruffleString string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().createWideStringFromString(emulatedPosixSupport, string); - } - return nativeLib.createWideStringFromString(nativePosixSupport, string); - } - - @ExportMessage - final TruffleString getCStringAsString(Object string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getCStringAsString(emulatedPosixSupport, string); - } - return nativeLib.getCStringAsString(nativePosixSupport, string); - } - - @ExportMessage - final Buffer getCStringAsBytes(Object string, - @CachedLibrary("this.nativePosixSupport") PosixSupportLibrary nativeLib) { - if (inPreInitialization) { - return PosixSupportLibrary.getUncached().getCStringAsBytes(emulatedPosixSupport, string); - } - return nativeLib.getCStringAsBytes(nativePosixSupport, string); + @Override + @TruffleBoundary + public final Object createCStringFromBytes(byte[] bytes) { + return getCurrentBackend().createCStringFromBytes(bytes); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index 92738a9cfd..5a21500c0a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -1458,6 +1458,9 @@ private void setupRuntimeInformation(boolean isPatching) { patchRuntimeInformation(); return; } + if (!env.isPreInitialization()) { + initializeHashSecret(); + } initializeLocale(); currentZoneId = env.getTimeZone(); setIntMaxStrDigits(getOption(PythonOptions.IntMaxStrDigits)); @@ -1480,8 +1483,23 @@ private void setupRuntimeInformation(boolean isPatching) { isInitialized = true; } + /** + * Runtime information of a pre-initialized context that was captured at image build time and + * must be taken from the run-time environment instead. The native compression supports are + * created without native access during pre-initialization (their native functions are + * {@code null}), so unless they are re-created here, {@code bz2}, {@code zlib} and {@code lzma} + * fail with a {@link NullPointerException} in native standalones. + */ private void patchRuntimeInformation() { initializeHashSecret(); + initializeLocale(); + currentZoneId = env.getTimeZone(); + setIntMaxStrDigits(getOption(PythonOptions.IntMaxStrDigits)); + if (!PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES) { + nativeZlib = NativeZlibSupport.createNative(this, ""); + nativeBz2lib = NativeBz2Support.createNative(this, ""); + nativeLZMA = NativeLZMASupport.createNative(this, ""); + } patchPackagePaths(T_STD_LIB_PLACEHOLDER, getStdlibHome()); repairFrozenPackagePaths(); isInitialized = true; @@ -2362,33 +2380,38 @@ public boolean setGilLockedDuringForeignCalls(boolean lock) { return old; } + @TruffleBoundary(allowInlining = true) + public TruffleFile getPublicTruffleFileRelaxed(TruffleString path) { + return getPublicTruffleFileRelaxed(path.toJavaStringUncached()); + } + /** * This is like {@code Env#getPublicTruffleFile(String)} but also allows access to files in the * language home directory matching one of the given file extensions. This is mostly useful to * access files of the {@code stdlib}, {@code core} or similar. */ @TruffleBoundary - public TruffleFile getPublicTruffleFileRelaxed(TruffleString path, TruffleString... allowedSuffixes) { - TruffleFile f = env.getInternalTruffleFile(path.toJavaStringUncached()); + public TruffleFile getPublicTruffleFileRelaxed(String path, String... allowedSuffixes) { + TruffleFile f = env.getInternalTruffleFile(path); // 'isDirectory' does deliberately not follow symlinks because otherwise this could allow to // escape the language home directory. // Also, during pre-initialization, we allow full internal access. if (env.isPreInitialization() || isPyFileInLanguageHome(f) && (f.isDirectory(LinkOption.NOFOLLOW_LINKS) || hasAllowedSuffix(path, allowedSuffixes))) { return f; } else { - return env.getPublicTruffleFile(path.toJavaStringUncached()); + return env.getPublicTruffleFile(path); } } - @TruffleBoundary(allowInlining = true) - private static boolean hasAllowedSuffix(TruffleString path, TruffleString[] allowedSuffixes) { - int pathLen = path.codePointLengthUncached(TS_ENCODING); - for (TruffleString suffix : allowedSuffixes) { - int suffixLen = suffix.codePointLengthUncached(TS_ENCODING); + private static boolean hasAllowedSuffix(String path, String[] allowedSuffixes) { + CompilerAsserts.neverPartOfCompilation(); + int pathLen = path.length(); + for (String suffix : allowedSuffixes) { + int suffixLen = suffix.length(); if (suffixLen > pathLen) { continue; } - if (path.regionEqualsUncached(pathLen - suffixLen, suffix, 0, suffixLen, TS_ENCODING)) { + if (path.endsWith(suffix)) { return true; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java index 37a5d4ef82..2c16b4003c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonImageBuildOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java index 962f9298e7..dc51eceb29 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java @@ -143,6 +143,9 @@ private PythonOptions() { @Option(category = OptionCategory.USER, help = "Equivalent to the Python -u flag. Force stdout and stderr to be unbuffered.", usageSyntax = "true|false", stability = OptionStability.STABLE) // public static final OptionKey UnbufferedIO = new OptionKey<>(false); + @Option(category = OptionCategory.USER, help = "Equivalent to setting the PYTHONLEGACYWINDOWSSTDIO environment variable for the standard launcher.", usageSyntax = "true|false", stability = OptionStability.STABLE) // + public static final OptionKey LegacyWindowsStdio = new OptionKey<>(false); + @Option(category = OptionCategory.USER, help = "Equivalent to the Python -I flag. Isolate from the users environment by not adding the cwd to the path", usageSyntax = "true|false", stability = OptionStability.STABLE) // public static final OptionKey IsolateFlag = new OptionKey<>(false); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java index 35e58a8b29..989b5a5c52 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java @@ -1579,8 +1579,8 @@ public static PPickleBuffer createPickleBuffer(Object view, Object cls, Shape sh return new PPickleBuffer(cls, shape, view); } - public static PPickler createPickler(PythonLanguage language) { - return createPickler(PythonBuiltinClassType.Pickler, PythonBuiltinClassType.Pickler.getInstanceShape(language)); + public static PPickler createPickler(PythonLanguage language, int outputCapacity, int memoCapacity) { + return new PPickler(PythonBuiltinClassType.Pickler, PythonBuiltinClassType.Pickler.getInstanceShape(language), outputCapacity, memoCapacity); } public static PPickler createPickler(Object cls, Shape shape) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java index 256bd20354..3f117403a6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/BoolSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.CompilerDirectives; public final class BoolSequenceStorage extends ArrayBasedSequenceStorage { @@ -122,7 +124,7 @@ public Object getCopyOfInternalArrayObject() { return PythonUtils.arrayCopyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -132,6 +134,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java index 2b752b5a92..6a5e12609c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.nio.ByteOrder; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import java.util.Arrays; import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary; @@ -141,7 +143,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -151,6 +153,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = getIntItemNormalized(i); } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java index 1a90f0fff4..897c29d998 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/DoubleSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java index a675b713c4..a1aaf8addb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ForeignSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -64,6 +64,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -229,6 +230,7 @@ static void clear(Node inliningTarget, ForeignSequenceStorage storage, for (int i = size - 1; i >= 0; i--) { removeNode.execute(inliningTarget, storage, i); } + LoopNode.reportLoopCount(inliningTarget, size); storage.setNewLength(0); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java index f450c1a47f..a3bdd83e39 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/IntSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java index fbbe102bfc..6e820e6219 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/LongSequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -26,6 +26,8 @@ package com.oracle.graal.python.runtime.sequence.storage; import java.util.Arrays; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; @@ -136,7 +138,7 @@ public Object getCopyOfInternalArrayObject() { return Arrays.copyOf(values, length); } - public Object[] getCopyOfInternalArray() { + public Object[] getCopyOfInternalArray(Node inliningTarget) { /* * Have to box and copy. */ @@ -146,6 +148,7 @@ public Object[] getCopyOfInternalArray() { boxed[i] = values[i]; } + LoopNode.reportLoopCount(inliningTarget, length); return boxed; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java index d7d98ffd7f..e09c50cdbb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java index 00ae70afde..a9ea0b1c10 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/SequenceStorageFactory.java @@ -25,13 +25,16 @@ */ package com.oracle.graal.python.runtime.sequence.storage; +import com.oracle.truffle.api.nodes.LoopNode; +import com.oracle.truffle.api.nodes.Node; + public abstract class SequenceStorageFactory { private SequenceStorageFactory() { // no instances } - public static SequenceStorage createStorage(Object[] values) { + public static SequenceStorage createStorage(Node inliningTarget, Object[] values) { assert values != null; assert values.getClass() == Object[].class : "cannot use non-Object array for modifiable list"; @@ -42,36 +45,38 @@ public static SequenceStorage createStorage(Object[] values) { return EmptySequenceStorage.INSTANCE; } - if (canSpecializeToInt(values)) { - return new IntSequenceStorage(specializeToInt(values)); - } else if (canSpecializeToDouble(values)) { - return new DoubleSequenceStorage(specializeToDouble(values)); - } else if (canSpecializeToLong(values)) { - return new LongSequenceStorage(specializeToLong(values)); - } else if (canSpecializeToBool(values)) { - return new BoolSequenceStorage(specializeToBool(values)); + if (canSpecializeToInt(inliningTarget, values)) { + return new IntSequenceStorage(specializeToInt(inliningTarget, values)); + } else if (canSpecializeToDouble(inliningTarget, values)) { + return new DoubleSequenceStorage(specializeToDouble(inliningTarget, values)); + } else if (canSpecializeToLong(inliningTarget, values)) { + return new LongSequenceStorage(specializeToLong(inliningTarget, values)); + } else if (canSpecializeToBool(inliningTarget, values)) { + return new BoolSequenceStorage(specializeToBool(inliningTarget, values)); } else { return new ObjectSequenceStorage(values); } } - private static boolean canSpecializeToInt(Object[] values) { - for (Object item : values) { - if (!(item instanceof Integer)) { + private static boolean canSpecializeToInt(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Integer)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static int[] specializeToInt(Object[] values) { + private static int[] specializeToInt(Node inliningTarget, Object[] values) { final int[] intVals = new int[values.length]; for (int i = 0; i < values.length; i++) { intVals[i] = (int) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return intVals; } @@ -95,63 +100,70 @@ private static byte[] specializeToByte(Object[] values) { return byteVals; } - private static boolean canSpecializeToLong(Object[] values) { - for (Object item : values) { + private static boolean canSpecializeToLong(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + Object item = values[i]; if (!(item instanceof Long || item instanceof Integer)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static long[] specializeToLong(Object[] values) { + private static long[] specializeToLong(Node inliningTarget, Object[] values) { final long[] intVals = new long[values.length]; for (int i = 0; i < values.length; i++) { long value = (values[i] instanceof Integer) ? (long) ((int) values[i]) : (long) values[i]; intVals[i] = value; } + LoopNode.reportLoopCount(inliningTarget, values.length); return intVals; } - private static boolean canSpecializeToDouble(Object[] values) { - for (Object item : values) { - if (!(item instanceof Double)) { + private static boolean canSpecializeToDouble(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Double)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static double[] specializeToDouble(Object[] values) { + private static double[] specializeToDouble(Node inliningTarget, Object[] values) { final double[] doubles = new double[values.length]; for (int i = 0; i < values.length; i++) { doubles[i] = (double) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return doubles; } - private static boolean canSpecializeToBool(Object[] values) { - for (Object item : values) { - if (!(item instanceof Boolean)) { + private static boolean canSpecializeToBool(Node inliningTarget, Object[] values) { + for (int i = 0; i < values.length; i++) { + if (!(values[i] instanceof Boolean)) { + LoopNode.reportLoopCount(inliningTarget, i); return false; } } - + LoopNode.reportLoopCount(inliningTarget, values.length); return true; } - private static boolean[] specializeToBool(Object[] values) { + private static boolean[] specializeToBool(Node inliningTarget, Object[] values) { final boolean[] bools = new boolean[values.length]; for (int i = 0; i < values.length; i++) { bools[i] = (boolean) values[i]; } + LoopNode.reportLoopCount(inliningTarget, values.length); return bools; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java index 66b8f999aa..d34b3c7652 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java @@ -97,6 +97,7 @@ import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.InvalidAssumptionException; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.nodes.NodeVisitor; @@ -803,6 +804,7 @@ public static TruffleString[] objectArrayToTruffleStringArray(Node inliningTarge for (int i = 0; i < array.length; i++) { result[i] = PythonUtils.internString(cast.execute(inliningTarget, array[i])); } + LoopNode.reportLoopCount(inliningTarget, array.length); return result; } @@ -922,11 +924,12 @@ public static Object pythonObjectFromConstantValue(ConstantValue v) { } } - public static long crc32(int initialValue, byte[] bytes, int offset, int length) { + public static long crc32(Node inliningTarget, int initialValue, byte[] bytes, int offset, int length) { int crc = ~initialValue; for (int i = 0; i < length; ++i) { crc = CRC_32_TAB[(crc ^ bytes[offset + i]) & 0xff] ^ (crc >>> 8); } + LoopNode.reportLoopCount(inliningTarget, length); return ~crc & 0xFFFFFFFFL; } @@ -965,11 +968,12 @@ public static long crc32(int initialValue, byte[] bytes, int offset, int length) 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - public static long crcHqx(int initialValue, byte[] bytes, int offset, int length) { + public static long crcHqx(Node inliningTarget, int initialValue, byte[] bytes, int offset, int length) { int crc = initialValue & 0xffff; for (int i = offset; i < length; i++) { crc = ((crc << 8) & 0xff00) ^ CRC_HQX_TAB[(crc >>> 8) ^ (bytes[i] & 0xff)]; } + LoopNode.reportLoopCount(inliningTarget, length - offset); return crc; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java index 40ea4fe9b4..d450438724 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/TimeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -40,7 +40,7 @@ */ package com.oracle.graal.python.util; -import com.oracle.graal.python.runtime.PosixSupportLibrary.Timeval; +import com.oracle.graal.python.runtime.PosixSupport.Timeval; public abstract class TimeUtils { public static final long SEC_TO_MS = 1000L; diff --git a/graalpython/lib-graalpython/_sysconfig.py b/graalpython/lib-graalpython/_sysconfig.py index f8bfb242ea..916e3de2ba 100644 --- a/graalpython/lib-graalpython/_sysconfig.py +++ b/graalpython/lib-graalpython/_sysconfig.py @@ -38,6 +38,9 @@ # SOFTWARE. +_DEFAULT_TZPATH = "/usr/share/zoneinfo:/usr/lib/zoneinfo:/usr/share/lib/zoneinfo:/etc/zoneinfo" + + def _append_flags(g, key, flags): value = g.get(key, "") parts = value.split() @@ -102,4 +105,8 @@ def _update_posix_vars(config_vars=None): _setdefault(config_vars, 'LIBDIR', __graalpython__.capi_home) _setdefault(config_vars, 'LIBDEST', __graalpython__.capi_home) _setdefault(config_vars, 'LIBPL', __graalpython__.capi_home.replace(os.path.sep, '/')) + if not win32_native: + # zoneinfo searches the system time zone database in TZPATH; use the + # locations CPython's configure uses by default (--with-tzpath) + _setdefault(config_vars, 'TZPATH', _DEFAULT_TZPATH) return config_vars diff --git a/graalpython/lib-graalpython/patches/cython-3.2.4.patch b/graalpython/lib-graalpython/patches/cython-3.2.4.patch index 2fa5ffd2a9..1307d88a10 100644 --- a/graalpython/lib-graalpython/patches/cython-3.2.4.patch +++ b/graalpython/lib-graalpython/patches/cython-3.2.4.patch @@ -256,6 +256,24 @@ index 8131c86..aa67eda 100644 #endif ((__pyx_CyFunctionObject *) func)->flags, ((__pyx_CyFunctionObject *) func)->func_qualname, +diff --git a/Cython/Utility/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c +index ddaffbd..c8e7962 100644 +--- a/Cython/Utility/ModuleSetupCode.c ++++ b/Cython/Utility/ModuleSetupCode.c +@@ -96,9 +96,11 @@ + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL +- #define CYTHON_METH_FASTCALL 0 ++ #define CYTHON_METH_FASTCALL 1 + #undef CYTHON_FAST_PYCALL +- #define CYTHON_FAST_PYCALL 0 ++ #define CYTHON_FAST_PYCALL 1 ++ #undef CYTHON_FAST_PYCCALL ++ #define CYTHON_FAST_PYCCALL 1 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif diff --git a/Cython/Utility/Optimize.c b/Cython/Utility/Optimize.c index b731f74..300758b 100644 --- a/Cython/Utility/Optimize.c diff --git a/graalpython/lib-graalpython/patches/cython-3.2.5.patch b/graalpython/lib-graalpython/patches/cython-3.2.5.patch new file mode 100644 index 0000000000..068ea43c42 --- /dev/null +++ b/graalpython/lib-graalpython/patches/cython-3.2.5.patch @@ -0,0 +1,315 @@ +diff --git a/Cython/Build/Dependencies.py b/Cython/Build/Dependencies.py +index 3726a72..ed46b9b 100644 +--- a/Cython/Build/Dependencies.py ++++ b/Cython/Build/Dependencies.py +@@ -1077,6 +1077,11 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + else: + dep_timestamp, dep = deps.newest_dependency(source) + priority = 2 - (dep in deps.immediate_dependencies(source)) ++ # GraalPy change: force recythonize if not cythonized by our patched version ++ if os.path.exists(c_file): ++ with open(c_file, 'rb') as f: ++ if not b'graalpy' in f.read(100): ++ c_timestamp = -1 + if force or c_timestamp < dep_timestamp: + if not quiet and not force: + if source == dep: +@@ -1130,6 +1135,8 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + for i, task in enumerate(to_compile, 1) + ] + ++ nthreads = 0 # GraalVM: we don't want to spawn ++ + if N <= 1: + nthreads = 0 + try: +diff --git a/Cython/Compiler/Version.py b/Cython/Compiler/Version.py +index 5ae2a4e..951aacc 100644 +--- a/Cython/Compiler/Version.py ++++ b/Cython/Compiler/Version.py +@@ -5,4 +5,4 @@ from .. import __version__ as version + + # For 'generated by' header line in C files. + +-watermark = str(version) ++watermark = f'{version}-graalpy' +diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd +index 2221ade..f46d197 100644 +--- a/Cython/Includes/cpython/array.pxd ++++ b/Cython/Includes/cpython/array.pxd +@@ -100,15 +100,18 @@ cdef extern from *: # Hard-coded utility code hack. + + cdef: + Py_ssize_t ob_size +- arraydescr* ob_descr # struct arraydescr *ob_descr; ++ ++ @property ++ cdef inline arraydescr* ob_descr(self) noexcept nogil: ++ return __Pyx_PyArray_Descr(self) + + @property + cdef inline __data_union data(self) noexcept nogil: + return __Pyx_PyArray_Data(self) + + array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) +- + __data_union __Pyx_PyArray_Data(array self) noexcept nogil ++ arraydescr* __Pyx_PyArray_Descr(array self) noexcept nogil + # fast resize/realloc + # not suitable for small increments; reallocation 'to the point' + int resize(array self, Py_ssize_t n) except -1 +@@ -120,15 +123,18 @@ 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.""" +- cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) ++ cdef arraydescr* descr = template.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(template), length, descr) + if zero and op is not None: +- memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) ++ memset(op.data.as_chars, 0, length * descr.itemsize) + return op + + cdef inline array copy(array self): + """ make a copy of an array. """ +- cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr) +- memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize) ++ cdef Py_ssize_t length = Py_SIZE(self) ++ cdef arraydescr* descr = self.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(self), length, descr) ++ memcpy(op.data.as_chars, self.data.as_chars, length * descr.itemsize) + return op + + cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1: +@@ -149,4 +155,4 @@ cdef inline int extend(array self, array other) except -1: + + cdef inline void zero(array self) noexcept: + """ set all elements of array to zero. """ +- memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize) ++ memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize) +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index 38e2f1c..7a4e223 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; +@@ -588,7 +604,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); +@@ -604,7 +620,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); +@@ -719,14 +735,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; +@@ -786,8 +802,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 +@@ -843,8 +861,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 +@@ -898,8 +918,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; + +@@ -1062,7 +1082,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)) { +@@ -1101,7 +1121,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)) { +@@ -1140,7 +1160,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)) { +@@ -1175,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_CyFunction_GetMethodDef(cyfunc)->ml_meth; + #endif + switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { + case 1: +@@ -1435,14 +1455,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/ModuleSetupCode.c b/Cython/Utility/ModuleSetupCode.c +index ddaffbd..c8e7962 100644 +--- a/Cython/Utility/ModuleSetupCode.c ++++ b/Cython/Utility/ModuleSetupCode.c +@@ -96,9 +96,11 @@ + #undef CYTHON_FAST_GIL + #define CYTHON_FAST_GIL 0 + #undef CYTHON_METH_FASTCALL +- #define CYTHON_METH_FASTCALL 0 ++ #define CYTHON_METH_FASTCALL 1 + #undef CYTHON_FAST_PYCALL +- #define CYTHON_FAST_PYCALL 0 ++ #define CYTHON_FAST_PYCALL 1 ++ #undef CYTHON_FAST_PYCCALL ++ #define CYTHON_FAST_PYCCALL 1 + #ifndef CYTHON_PEP487_INIT_SUBCLASS + #define CYTHON_PEP487_INIT_SUBCLASS 1 + #endif +diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h +index bc6da7b..6bf0559 100644 +--- a/Cython/Utility/arrayarray.h ++++ b/Cython/Utility/arrayarray.h +@@ -69,10 +69,27 @@ struct arrayobject { + int ob_exports; /* Number of exported buffers */ + }; + ++#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM >= 0x190304a0 ++#define __PYX_USE_GRAALPY_ARRAY_API 1 ++#else ++#define __PYX_USE_GRAALPY_ARRAY_API 0 ++#endif ++ ++static CYTHON_INLINE struct arraydescr *__Pyx_PyArray_Descr(arrayobject *self) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return (struct arraydescr *)GraalPyArray_GetDescriptor((PyObject*)self); ++#else ++ return self->ob_descr; ++#endif ++} ++ + #ifndef NO_NEWARRAY_INLINE + // fast creation of a new array + static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, + struct arraydescr *descr) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return GraalPyArray_New((PyObject*)type, size, (GraalPyArray_Descriptor*)descr); ++#else + arrayobject *op; + size_t nbytes; + +@@ -105,6 +122,7 @@ static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t si + } + } + return (PyObject *) op; ++#endif + } + #else + PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, diff --git a/graalpython/lib-graalpython/patches/cython-3.3.0.patch b/graalpython/lib-graalpython/patches/cython-3.3.0.patch new file mode 100644 index 0000000000..e9f7d1e465 --- /dev/null +++ b/graalpython/lib-graalpython/patches/cython-3.3.0.patch @@ -0,0 +1,290 @@ +diff --git a/Cython/Build/Dependencies.py b/Cython/Build/Dependencies.py +index a38cb31..367e0b2 100644 +--- a/Cython/Build/Dependencies.py ++++ b/Cython/Build/Dependencies.py +@@ -1077,6 +1077,11 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + else: + dep_timestamp, dep = deps.newest_dependency(source) + priority = 2 - (dep in deps.immediate_dependencies(source)) ++ # GraalPy change: force recythonize if not cythonized by our patched version ++ if os.path.exists(c_file): ++ with open(c_file, 'rb') as f: ++ if not b'graalpy' in f.read(100): ++ c_timestamp = -1 + if force or c_timestamp < dep_timestamp: + if not quiet and not force: + if source == dep: +@@ -1130,6 +1135,8 @@ def cythonize(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, + for i, task in enumerate(to_compile, 1) + ] + ++ nthreads = 0 # GraalVM: we don't want to spawn ++ + if N <= 1: + nthreads = 0 + try: +diff --git a/Cython/Compiler/Version.py b/Cython/Compiler/Version.py +index 5ae2a4e..951aacc 100644 +--- a/Cython/Compiler/Version.py ++++ b/Cython/Compiler/Version.py +@@ -5,4 +5,4 @@ from .. import __version__ as version + + # For 'generated by' header line in C files. + +-watermark = str(version) ++watermark = f'{version}-graalpy' +diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd +index d5352a0..9640254 100644 +--- a/Cython/Includes/cpython/array.pxd ++++ b/Cython/Includes/cpython/array.pxd +@@ -100,15 +100,18 @@ cdef extern from *: # Hard-coded utility code hack. + + cdef: + Py_ssize_t ob_size +- arraydescr* ob_descr # struct arraydescr *ob_descr; ++ ++ @property ++ cdef inline arraydescr* ob_descr(self) noexcept nogil: ++ return __Pyx_PyArray_Descr(self) + + @property + cdef inline __data_union data(self) noexcept nogil: + return __Pyx_PyArray_Data(self) + + array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) +- + __data_union __Pyx_PyArray_Data(array self) noexcept nogil ++ arraydescr* __Pyx_PyArray_Descr(array self) noexcept nogil + # fast resize/realloc + # not suitable for small increments; reallocation 'to the point' + int resize(array self, Py_ssize_t n) except -1 +@@ -120,15 +123,18 @@ 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.""" +- cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) ++ cdef arraydescr* descr = template.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(template), length, descr) + if zero and op is not None: +- memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) ++ memset(op.data.as_chars, 0, length * descr.itemsize) + return op + + cdef inline array copy(array self): + """ make a copy of an array. """ +- cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr) +- memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize) ++ cdef Py_ssize_t length = Py_SIZE(self) ++ cdef arraydescr* descr = self.ob_descr ++ cdef array op = newarrayobject(Py_TYPE(self), length, descr) ++ memcpy(op.data.as_chars, self.data.as_chars, length * descr.itemsize) + return op + + cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1: +diff --git a/Cython/Utility/CythonFunction.c b/Cython/Utility/CythonFunction.c +index d4c5107..2b3c7b8 100644 +--- a/Cython/Utility/CythonFunction.c ++++ b/Cython/Utility/CythonFunction.c +@@ -100,6 +100,22 @@ typedef struct { + #endif + } __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) +@@ -268,7 +284,7 @@ __Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + const char *doc = op->func_methoddef->ml_doc; + #else +- const char *doc = ((PyCFunctionObject*)op)->m_ml->ml_doc; ++ const char *doc = __Pyx_CyFunction_GetDoc(op); + #endif + if (doc) { + op->func_doc = PyUnicode_FromString(doc); +@@ -317,7 +333,7 @@ __Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) + #if CYTHON_COMPILING_IN_LIMITED_API + const char *name = op->func_methoddef->ml_name; + #else +- const char *name = ((PyCFunctionObject*)op)->m_ml->ml_name; ++ const char *name = __Pyx_CyFunction_GetMethodDef(op)->ml_name; + #endif + op->func_name = PyUnicode_InternFromString(name); + if (unlikely(op->func_name == NULL)) +@@ -840,7 +856,7 @@ static void __Pyx_CyFunction_raise_argument_count_error(PyObject *func, const ch + 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); +@@ -856,7 +872,7 @@ static void __Pyx_CyFunction_raise_type_error(PyObject *func, const char* messag + 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); +@@ -1013,7 +1029,7 @@ static PyObject *__Pyx_CyFunction_Init(PyObject *op_in, + op->flags = flags; + __Pyx_CyFunction_weakreflist(op) = NULL; + #if !CYTHON_COMPILING_IN_LIMITED_API +- cf->m_ml = ml; ++ __Pyx_CyFunction_SetMethodDef(cf, ml); + // This is set for the benefit of __Pyx_CyOrPyCFunction_GET_SELF. It is never reassigned, so + // when we know an object is a CyFunction we don't even need to look it up.__Pyx_CyFunction_set_module + cf->m_self = (PyObject *) op; +@@ -1022,7 +1038,7 @@ static PyObject *__Pyx_CyFunction_Init(PyObject *op_in, + 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; +@@ -1083,8 +1099,10 @@ static int __Pyx__CyFunction_clear(__pyx_CyFunctionObject *m) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_CLEAR(m->func_module); + #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 +@@ -1150,8 +1168,10 @@ static int __Pyx_CyFunction_traverse(PyObject *m_in, visitproc visit, void *arg) + #if CYTHON_COMPILING_IN_LIMITED_API + Py_VISIT(m->func_module); + #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 +@@ -1204,8 +1224,8 @@ static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, Py + int flags = cyfunc->func_methoddef->ml_flags; + #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; + +@@ -1361,7 +1381,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *c + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + 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(func, cyfunc, nargs, kwnames)) { +@@ -1394,7 +1414,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + 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(func, cyfunc, nargs, kwnames)) { +@@ -1427,7 +1447,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + 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(func, cyfunc, nargs, NULL)) { +@@ -1456,7 +1476,7 @@ static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject + PyCFunction meth = cyfunc->func_methoddef->ml_meth; + 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(func, cyfunc, nargs, NULL)) { + case 1: +@@ -1752,14 +1772,14 @@ __pyx_FusedFunction_descr_get_locked(PyObject *self, PyObject *obj) + module = __Pyx_CyFunction_get_module(self, NULL); + if ((unlikely(!module))) return NULL; + #else +- module = ((PyCFunctionObject *) func)->m_module; ++ module = __Pyx_CyFunction_GetModule(func); + #endif + + meth = __pyx_FusedFunction_New( + #if CYTHON_COMPILING_IN_LIMITED_API + func->ml, + #else +- ((PyCFunctionObject *) func)->m_ml, ++ __Pyx_CyFunction_GetMethodDef(func), + #endif + cyfunc->flags, + cyfunc->func_qualname, +diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h +index 629b28f..ff2618c 100644 +--- a/Cython/Utility/arrayarray.h ++++ b/Cython/Utility/arrayarray.h +@@ -69,10 +69,27 @@ struct arrayobject { + int ob_exports; /* Number of exported buffers */ + }; + ++#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM >= 0x190304a0 ++#define __PYX_USE_GRAALPY_ARRAY_API 1 ++#else ++#define __PYX_USE_GRAALPY_ARRAY_API 0 ++#endif ++ ++static CYTHON_INLINE struct arraydescr *__Pyx_PyArray_Descr(arrayobject *self) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return (struct arraydescr *)GraalPyArray_GetDescriptor((PyObject*)self); ++#else ++ return self->ob_descr; ++#endif ++} ++ + #ifndef NO_NEWARRAY_INLINE + // fast creation of a new array + static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t size, + struct arraydescr *descr) { ++#if __PYX_USE_GRAALPY_ARRAY_API ++ return GraalPyArray_New((PyObject*)type, size, (GraalPyArray_Descriptor*)descr); ++#else + arrayobject *op; + size_t nbytes; + +@@ -105,6 +122,7 @@ static CYTHON_INLINE PyObject * newarrayobject(PyTypeObject *type, Py_ssize_t si + } + } + return (PyObject *) op; ++#endif + } + #else + PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size, diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml index 033fb7ce4f..8e1d29cfcb 100644 --- a/graalpython/lib-graalpython/patches/metadata.toml +++ b/graalpython/lib-graalpython/patches/metadata.toml @@ -93,6 +93,18 @@ license = 'Apache-2.0 OR BSD-3-Clause' version = '>= 43.0.0' note = "Versions newer than 43 do not need a patch." +[[cython.rules]] +version = '== 3.3.0' +autopatch = false +patch = 'cython-3.3.0.patch' +license = 'Apache-2.0' + +[[cython.rules]] +version = '>= 3.2.5, <= 3.2.9' +autopatch = false +patch = 'cython-3.2.5.patch' +license = 'Apache-2.0' + [[cython.rules]] version = '>= 3.2.0, < 3.2.4' autopatch = false diff --git a/graalpython/python-libposix/src/posix.c b/graalpython/python-libposix/src/posix.c index df8d2bb45b..ae205e8e31 100644 --- a/graalpython/python-libposix/src/posix.c +++ b/graalpython/python-libposix/src/posix.c @@ -1161,6 +1161,123 @@ GP_EXPORT int64_t call_write(int32_t fd, void *buf, uint64_t count) { return write_noraise(fd, buf, count > INT_MAX ? INT_MAX : (unsigned int) count); } +GP_EXPORT int32_t call_get_windows_console_type(int32_t fd) { + intptr_t osfhandle = get_osfhandle_noraise(fd); + if (osfhandle == -1) { + return 0; + } + HANDLE handle = (HANDLE) osfhandle; + DWORD mode; + if (!GetConsoleMode(handle, &mode)) { + return 0; + } + DWORD event_count; + return GetNumberOfConsoleInputEvents(handle, &event_count) ? 'r' : 'w'; +} + +/* Copied from CPython's Modules/_io/winconsoleio.c (_find_last_utf8_boundary). */ +static uint32_t find_last_utf8_boundary(const unsigned char *buf, uint32_t len) { + for (uint32_t count = 1; count < 4 && count <= len; count++) { + unsigned char c = buf[len - count]; + if (c < 0x80) { + return len; + } + if (c >= 0xc0) { + if (c < 0xe0 ? count < 2 : c < 0xf0 ? count < 3 : c < 0xf8 ? count < 4 : 0) { + return len - count; + } + return len; + } + } + return len; +} + +static uint32_t wchar_to_utf8_count(const unsigned char *s, uint32_t len, uint32_t n) { + uint32_t start = 0; + while (1) { + uint32_t mid = 0; + for (uint32_t i = len / 2; i <= len; i++) { + mid = find_last_utf8_boundary(s, i); + if (mid != 0) { + break; + } + } + if (mid == len) { + uint32_t wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) s, len, NULL, 0); + return wlen <= n ? start + len : start; + } + if (mid == 0) { + mid = len > 1 ? len - 1 : 1; + } + uint32_t wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) s, mid, NULL, 0); + if (wlen <= n) { + s += mid; + start += mid; + len -= mid; + n -= wlen; + } else { + len = mid; + } + } +} + +GP_EXPORT int64_t call_write_windows_console(int32_t fd, const unsigned char *buf, uint64_t count) { + intptr_t osfhandle = get_osfhandle_noraise(fd); + if (osfhandle == -1) { + capture_errno(); + return -1; + } + if (count == 0) { + return 0; + } + + const uint32_t max_wlen = 32766U / sizeof(wchar_t); + // Like CPython, write at most one bounded chunk and let the caller handle partial writes. + uint32_t len = count > max_wlen * 3U ? max_wlen * 3U : (uint32_t) count; + uint32_t wlen; + while (1) { + uint32_t boundary = find_last_utf8_boundary(buf, len); + // If the whole chunk is incomplete UTF-8, convert it to replacement characters rather + // than returning zero forever when a buffered caller tries to flush it. + if (boundary != 0) { + len = boundary; + } + wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) buf, len, NULL, 0); + if (wlen == 0) { + set_win_errno(GetLastError()); + return -1; + } + if (wlen <= max_wlen) { + break; + } + len /= 2; + } + + wchar_t *wbuf = (wchar_t *) malloc(wlen * sizeof(wchar_t)); + if (wbuf == NULL) { + set_posix_errno(ENOMEM); + return -1; + } + wlen = MultiByteToWideChar(CP_UTF8, 0, (const char *) buf, len, wbuf, wlen); + DWORD written = 0; + BOOL result = wlen && WriteConsoleW((HANDLE) osfhandle, wbuf, wlen, &written, NULL); + if (!result) { + DWORD error = GetLastError(); + free(wbuf); + set_win_errno(error); + return -1; + } + free(wbuf); + if (written < wlen) { + len = wchar_to_utf8_count(buf, len, written); + } + if (len == 0) { + set_posix_errno(EIO); + return -1; + } + return len; +} + GP_EXPORT int32_t call_dup(int32_t fd) { if (win_socket_entry_index(fd) >= 0) { return win_socket_dup(fd); @@ -2443,6 +2560,20 @@ int64_t call_write(int32_t fd, void *buf, uint64_t count) { CAPTURE_ERRNO_AND_RETURN(-1, write(fd, buf, count)); } +int32_t call_get_windows_console_type(int32_t fd) { + (void) fd; + return 0; +} + +int64_t call_write_windows_console(int32_t fd, const void *buf, uint64_t count) { + (void) fd; + (void) buf; + (void) count; + errno = ENOSYS; + capture_errno(); + return -1; +} + int32_t call_dup(int32_t fd) { CAPTURE_ERRNO_AND_RETURN(-1, fcntl(fd, F_DUPFD_CLOEXEC, 0)); } diff --git a/mx.graalpython/copyrights/overrides b/mx.graalpython/copyrights/overrides index 556e94fda8..36df899701 100644 --- a/mx.graalpython/copyrights/overrides +++ b/mx.graalpython/copyrights/overrides @@ -33,6 +33,7 @@ graalpython/com.oracle.graal.python.benchmarks/python/meso/spectralnorm3.py,benc graalpython/com.oracle.graal.python.benchmarks/python/meso/threadring.py,benchmarks.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-binop.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/arith-modulo-sized.py,zippy.copyright +graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-megamorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access-polymorphic.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-access.py,zippy.copyright graalpython/com.oracle.graal.python.benchmarks/python/micro/attribute-bool.py,zippy.copyright diff --git a/mx.graalpython/mx_graalpython_bench_param.py b/mx.graalpython/mx_graalpython_bench_param.py index 3100fa3cfe..9ad50704fe 100644 --- a/mx.graalpython/mx_graalpython_bench_param.py +++ b/mx.graalpython/mx_graalpython_bench_param.py @@ -64,6 +64,7 @@ MICRO_BENCHMARKS = { 'arith-binop': ITER_10 + ['5'], 'arith-modulo-sized': ITER_10 + ['500'], + 'attribute-access-megamorphic': ITER_10 + ['200'], 'attribute-access-polymorphic': ITER_10 + ['1000'], 'attribute-access': ITER_15 + ['5000'], 'attribute-access-super': ITER_20 + ['5_000'], @@ -161,6 +162,7 @@ 'if-generic': ITER_10 + WARMUP_2 + ['500000'], 'if-generic-non-builtin': ITER_10 + WARMUP_2 + ['500000'], 'if-polymorph': ITER_10 + WARMUP_2 + ['1000000'], + 'attribute-access-megamorphic': ITER_6 + WARMUP_2 + ['13'], 'attribute-access-polymorphic': ITER_6 + WARMUP_2 + ['20'], 'attribute-access': ITER_6 + WARMUP_2 + ['100'], 'attribute-access-super': ITER_6 + WARMUP_2 + ['40'],