Skip to content

[GR-49501] Move C API helpers to C implementations#803

Open
graalvmbot wants to merge 17 commits intomasterfrom
tim/GR-49501-eager-native-operations
Open

[GR-49501] Move C API helpers to C implementations#803
graalvmbot wants to merge 17 commits intomasterfrom
tim/GR-49501-eager-native-operations

Conversation

@graalvmbot
Copy link
Copy Markdown
Collaborator

No description provided.

timfel added 17 commits May 6, 2026 07:18
Move the public PyCallable_Check symbol from the Java direct builtin to the existing C implementation in object.c and register it as CImpl in CApiFunction. Remove the Java PyCallable_Check builtin and unused PyCallableCheckNode import.

Temporary benchmark coverage used for measurement: a c-pycallable-check microbenchmark covering a native callable with tp_call, a native non-callable object, and NULL-safe behavior. The temporary benchmark and benchmark registration were removed before committing per PLAN.org.

Verification:

- mx python-jvm passed.

- JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed.

- mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_object.py::tests.cpyext.test_object.TestObjectFunctions.test_PyCallable_Check passed: Ran 1 tests in 61.80s, OK (passed=1).

- mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/ passed: Ran 2807 tests in 800.33s, OK (passed=2788, skipped=19).

Benchmark command shape:

<graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pycallable-check.py 100000000

Benchmark quietness: observed the machine with vmstat 5 13 before both baseline and current measurements. The pre-baseline and pre-current windows were mostly r=0 with 99-100% idle after the initial sample, and no active build/test process was visible among top CPU consumers.

Baseline measurement used a native standalone built with this implementation patch temporarily reversed and copied to /tmp/graalpy-pycallable-baseline-20260505-135844. Raw durations: [15.764891772, 15.176673579, 15.133897106, 15.679905815, 15.067935304, 14.92753357, 15.24439545, 14.782456798, 15.072720261]. Median: 15.133897106 s; best: 14.782456798 s; worst: 15.764891772 s; spread: 0.982434974 s.

Current C implementation measurement raw durations: [0.295874113, 0.29998132, 0.30158966, 0.291079724, 0.288517571, 0.295749312, 0.29998344, 0.287563849, 0.287959175]. Median: 0.295749312 s; best: 0.287563849 s; worst: 0.30158966 s; spread: 0.014025811 s.

Conclusion: moving PyCallable_Check from the Java direct builtin to the C implementation improves this native no-compilation benchmark by about 51.17x by median time.
Move the public PyObject_IsTrue C API symbol from the Java direct builtin to the C implementation in object.c and register it as CImpl. Preserve managed-object behavior with a narrow GraalPyPrivate_Object_IsTrue raw-pointer Java fallback implemented as a static CApiBuiltin method, matching the existing static-helper pattern instead of introducing a CApiBuiltin node class.

Verification: mx python-jvm passed (mxbuild/buildlog-20260505-143336.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed for the final implementation (mxbuild/buildlog-20260505-150119.html). Focused cpyext tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py::tests.cpyext.test_functions.TestPyObject.test_PyObject_IsTrue graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py::tests.cpyext.test_functions.TestPyObject.test_PyObject_Not graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_nb_bool.py::test_from_python; result: Ran 3 tests in 1.03s, OK (passed=3). Full test suite passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/; result: Ran 2807 tests in 705.34s, OK (passed=2788, skipped=19). git diff --check passed.

Temporary benchmark: added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pyobject-istrue.py during measurement, covering Py_True, Py_False, Py_None, nb_bool, mapping length, sequence length, and default truthy native-object paths; removed it before commit per PLAN.org. Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pyobject-istrue.py 5000000.

Benchmark quietness: before baseline and current measurements, observed the machine with vmstat 5 13 for about a minute. The windows were mostly r=0 with 99-100% idle after the initial sample, and ps showed no active build/test process; Emacs was the top process at about 5.6% CPU.

Baseline: native standalone built with the implementation patch temporarily reversed and copied to /tmp/graalpy-pyobject-istrue-baseline-20260505-145638. Raw durations: [4.215643798, 4.200535418, 4.220929938, 4.25846425, 4.179787468, 4.173013933, 4.190631835, 4.118770273, 4.025052785]. Median: 4.190631835 s; best: 4.025052785 s; worst: 4.25846425 s; spread: 0.233411465 s.

Current: raw durations: [0.175453561, 0.179316962, 0.177278654, 0.168218284, 0.170692362, 0.173828127, 0.168950964, 0.180557498, 0.181329358]. Median: 0.175453561 s; best: 0.168218284 s; worst: 0.181329358 s; spread: 0.013111074 s. Conclusion: moving PyObject_IsTrue from the Java direct builtin to the C implementation improves this native no-compilation benchmark by about 23.88x by median time.
Register PyIter_Check as a CImpl C API function and remove the Java direct builtin. The CPython iterator block in abstract.c is disabled in GraalPy, so add a compiled PyIter_Check definition outside that disabled block to provide the native symbol.

Verification: mx python-jvm passed (mxbuild/buildlog-20260505-174000.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260505-174622.html; current rebuilt for benchmarking at mxbuild/buildlog-20260505-180655.html). Focused cpyext test passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py::test_tp_iternext_not_implemented, Ran 1 tests in 0.10s, OK (passed=1). Full test suite passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/, Ran 2807 tests in 679.17s, OK (passed=2788, skipped=19).

Benchmark: temporarily added c-pyiter-check.py covering a native iterator with tp_iternext, a native sequence-like iterable that is not itself an iterator, and a native non-iterator object; removed the temporary benchmark before committing. Quietness checks before both measurements used vmstat 5 13 and top CPU process snapshots; windows were mostly r=0/r=1 with 98-100% idle after the initial sample, with Emacs the top process at about 7.7% CPU.

Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pyiter-check.py 30000000. Baseline used /tmp/graalpy-pyiter-check-baseline-20260505-180231 built with this implementation patch temporarily reversed. Baseline raw durations: [6.189263866, 6.309805407, 6.338300861, 6.279226039, 6.268628357, 6.309469413, 6.320189933, 6.335439071, 6.284029805]; median 6.309469413 s, best 6.189263866 s, worst 6.338300861 s, spread 0.149036995 s. Current raw durations: [0.126759258, 0.129113078, 0.129032669, 0.126353708, 0.131626644, 0.127087841, 0.126351596, 0.124293469, 0.124502626]; median 0.126759258 s, best 0.124293469 s, worst 0.131626644 s, spread 0.007333175 s. Conclusion: about 49.78x faster by median time.
Move the public PyObject_GetIter entry point from the Java direct builtin to the C implementation in abstract.c and register it as CImpl in CApiFunction.

The compiled C implementation lives outside the disabled CPython iterator block, like PyIter_Check. It uses the native tp_iter / PySequence_Check / PySeqIter_New logic for native objects and preserves managed-object behavior through a narrow GraalPyPrivate_Object_GetIter raw-pointer Java fallback.

Temporary benchmark: added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pyobject-getiter.py covering a native tp_iter object, sequence fallback through PySeqIter_New, and one non-iterable TypeError correctness check; removed it before committing per PLAN.org.

Verification: mx python-jvm passed (mxbuild/buildlog-20260505-181713.html). Focused cpyext tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py::tests.cpyext.test_functions.TestPyObject.test_PyObject_GetIter graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py::tests.cpyext.test_functions.TestPyObject.test_PyObject_SelfIter graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py::test_tp_iter_iternext_calls; result: Ran 3 tests in 0.45s, OK (passed=3). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260505-182348.html; current rebuilt for benchmarking at mxbuild/buildlog-20260505-184436.html). Full suite passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/; result: Ran 2807 tests in 700.30s, OK (passed=2788, skipped=19).

Benchmark quietness: before baseline and current measurements, observed the machine with vmstat 5 13 for about a minute. Both windows were mostly r=0 with 99-100% idle after the initial sample, and no active build/test process was visible among top CPU consumers; Emacs was the top process at about 8.2% CPU.

Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pyobject-getiter.py 5000000.

Baseline: native standalone built with this implementation patch temporarily reversed and copied to /tmp/graalpy-pyobject-getiter-baseline-20260505-184016. Raw durations: [5.662864924, 5.77716436, 5.865396065, 5.926168834, 5.827736089, 5.911669503, 5.892751251, 5.92403813, 5.842762165]. Median: 5.865396065 s; best: 5.662864924 s; worst: 5.926168834 s; spread: 0.26330391 s.

Current: raw durations: [3.84010954, 3.878019773, 3.899857059, 3.925100635, 3.966473596, 3.925557547, 3.915327162, 3.934049151, 3.905884266]. Median: 3.915327162 s; best: 3.84010954 s; worst: 3.966473596 s; spread: 0.126364056 s.

Conclusion: moving PyObject_GetIter from the Java direct builtin to the hybrid C implementation improves this native no-compilation benchmark by about 1.50x by median time.
Move PyDict_Size out of the Java direct builtin registry and register it as a CImpl entry in CApiFunction. The existing upstream PyDict_Size body in dictobject.c is inside a disabled GraalPy #if 0 block, so add the active C implementation in the compiled GraalPy section near dict_dealloc. The implementation keeps wrong-type behavior through PyErr_BadInternalCall, uses GraalPyPrivate_Object_Size for managed dict and dict subclass objects, and reads ma_used directly for native dict objects.

Verification: mx python-jvm passed (mxbuild/buildlog-20260505-204056.html before final JVM rebuild; final current rebuild passed at mxbuild/buildlog-20260505-205446.html). Focused cpyext command passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py::tests.cpyext.test_dict.TestPyDict.test_PyDict_Size graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py::tests.cpyext.test_functions.TestPyObject.test_PyObject_Call. Full dict cpyext file passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py (22 tests). Native builds passed with JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm for current (mxbuild/buildlog-20260505-204651.html) and for the temporarily reversed baseline (mxbuild/buildlog-20260505-205117.html).

Temporary benchmark: added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pydict-size.py during investigation only, covering managed exact dict, C-created exact dict, dict subclass correctness, and wrong-type SystemError correctness; removed it before commit per PLAN.org. Quietness check before measurement: vmstat 5 13 over about one minute showed 100% idle after the initial historical line and run queue 0 or 1; ps showed no active build/test CPU-heavy process.

Benchmark command: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pydict-size.py 10000000. Baseline Java-direct standalone was built with the PyDict_Size patch temporarily reversed and copied to /tmp/graalpy-pydict-size-baseline-20260505-2051. Baseline raw durations: [1.432521117, 1.378349267, 1.390894927, 1.38433802, 1.443656571, 1.43790804, 1.43800257, 1.413966472, 1.417834157]; best 1.378s, worst 1.444s, average 1.415s, median 1.418s. Current CImpl standalone was /tmp/graalpy-pydict-size-current-20260505-2047. Current raw durations: [0.941734285, 0.937482254, 0.941674476, 0.919298855, 0.928701666, 0.935161315, 0.948869297, 0.941842147, 0.940401473]; best 0.919s, worst 0.949s, average 0.937s, median 0.940s. Conclusion: about 1.51x faster by median time.
Move _PyNumber_Index from the shared Java-direct PyNumber_Index builtin to the C implementation in abstract.c and register only _PyNumber_Index as CImpl. Keep public PyNumber_Index Java-direct for the separate TODO so exact-int copy semantics remain unchanged there.

Add GraalPyPrivate_PyNumber_Index as the managed-object fallback. It preserves CPython _PyNumber_Index behavior: existing int subclasses are returned directly, __index__ results may be int subclasses, and non-int results raise TypeError. Add cpyext coverage that distinguishes exact int from bool and custom int-subclass results.

Verification: mx python-jvm passed (mxbuild/buildlog-20260505-222959.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260505-223449.html; final native focused rebuild at mxbuild/buildlog-20260505-223828.html). Focused JVM tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py::tests.cpyext.test_abstract.TestAbstract.test__PyNumber_Index graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py::tests.cpyext.test_abstract.TestAbstract.test_PyNumber_Index, Ran 2 tests in 1.84s, OK (passed=2). Focused native tests passed with pinned JAVA_HOME/LATEST_JAVA_HOME and GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true: mx graalpytest --svm for the same two tests, Ran 2 tests in 1.38s, OK (passed=2). Full suite passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/ --mx-report /tmp/pynumber-index-full-report.json, Ran 2808 tests in 694.67s, OK (passed=2789, skipped=19).

Benchmark: temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pynumber-index.py and removed it before committing. Command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pynumber-index.py 10000000. Quietness was checked with vmstat 5 13 before current and baseline; both windows were mostly r=0 with 99-100% idle after the initial historical sample and no active build/test CPU-heavy process visible; Emacs was the top sustained process at about 16.5% of one CPU.

Current CImpl measurement used /tmp/graalpy-pynumber-index-current-20260505-2152. Raw durations: [0.399217322, 0.386455915, 0.390759825, 0.387381291, 0.404902442, 0.385551238, 0.385262956, 0.385844885, 0.392532917]. Best 0.385s, worst 0.405s, average 0.391s, median 0.387s. Baseline Java-direct measurement used /tmp/graalpy-pynumber-index-baseline-20260505-2225. Raw durations: [1.699626159, 1.693498868, 1.689648931, 1.694836749, 1.695359309, 1.693872535, 1.702244645, 1.693211745, 1.721866315]. Best 1.690s, worst 1.722s, average 1.698s, median 1.695s.

The benchmark setup initially caught a semantic difference in the baseline: Java-direct _PyNumber_Index returned exact int for bool/int-subclass cases where CPython preserves the subclass. The timing setup was relaxed to measure the old path, while the permanent cpyext test keeps the stricter behavior check. Conclusion: moving _PyNumber_Index to CImpl improves this native no-compilation benchmark by about 4.38x by median time and fixes the private API's int-subclass return semantics.
Move PyNumber_Index from the Java-direct C API builtin to the existing C implementation in abstract.c and register it as CImpl in CApiFunction.

Preserve CPython exact-int copy semantics for managed int subclasses with a narrow GraalPyPrivate_PyNumber_IndexCopy fallback used only when the C implementation receives a managed non-exact long result. Native non-exact longs still use _PyLong_Copy.

Tighten cpyext coverage for PyNumber_Index to return (Py_TYPE(result)->tp_name, result), distinguishing exact int results from bool and int subclasses. Add coverage for an object whose __index__ returns an int subclass.

Full-suite verification initially caught that calling _PyLong_Copy directly on a managed int-subclass result reaches the not-implemented C API route. The managed-copy fallback fixes this while keeping the public entry point in C.

Verification: mx python-jvm passed (final source rebuild at mxbuild/buildlog-20260505-233849.html; earlier validation rebuild after the managed-copy fix at mxbuild/buildlog-20260505-230417.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (final source rebuild at mxbuild/buildlog-20260505-234340.html; final native focused rebuild at mxbuild/buildlog-20260505-234724.html).

Focused JVM tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py::tests.cpyext.test_abstract.TestAbstract.test_PyNumber_Index graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py::tests.cpyext.test_abstract.TestAbstract.test__PyNumber_Index graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py::tests.cpyext.test_abstract.TestAbstract.test_PyNumber_AsSsize_t, Ran 3 tests in 1.77s, OK (passed=3). Focused native tests passed with pinned JAVA_HOME/LATEST_JAVA_HOME and GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true for the same tests, Ran 3 tests in 1.80s, OK (passed=3). Full suite passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/ --mx-report /tmp/pynumber-index-public-full-report.json, Ran 2808 tests in 729.54s, OK (passed=2789, skipped=19).

Benchmark: temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pynumber-index-public.py and removed it before committing. The benchmark measured exact int and native nb_index exact-int paths in the timed loop, with one-time correctness checks for non-index TypeError and managed __index__ returning an int subclass that must be copied to exact int. A first attempt to time the int-subclass-return path every iteration was stopped because repeated deprecation-warning processing dominated runtime.

Benchmark command: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pynumber-index-public.py 10000000. Quietness was checked with vmstat 5 13 before current and baseline. The current window was mostly r=0 with 99-100% idle after the initial historical sample; the baseline window was r=0/r=1 with 99-100% idle after the initial historical sample. ps showed no active build/test CPU-heavy process; Emacs was the top sustained process at about 16% of one CPU.

Current CImpl measurement used /tmp/graalpy-pynumber-index-public-current-20260505-2327. Raw durations: [0.596066757, 0.611307405, 0.616138294, 0.601266838, 0.604464302, 0.610334569, 0.608268694, 0.609358989, 0.592895327]. Best 0.593s, worst 0.616s, average 0.606s, median 0.608s.

Baseline Java-direct measurement used /tmp/graalpy-pynumber-index-public-baseline-20260505-2335. Raw durations: [1.887633857, 1.898408786, 1.939036876, 1.912759437, 1.902811571, 1.891698046, 1.914234673, 1.913143756, 1.893450307]. Best 1.888s, worst 1.939s, average 1.906s, median 1.903s. Conclusion: moving PyNumber_Index to CImpl improves this native no-compilation benchmark by about 3.13x by median time while preserving exact-int copy semantics.
Register PyLong_FromUnsignedLong as a CImpl entry point and enable the public C symbol in longobject.c. The C path returns tagged int32 pointers directly for small unsigned values and calls the private GraalPyPrivate_Long_FromUnsignedLong static C API helper for values requiring an unsigned multi-digit Python int. A pure CPython-style C implementation is still blocked because _PyLong_New is not available through this route (Function not implemented in GraalPy: _PyLong_New), so the large-value path intentionally falls back to Java object creation.

Add cpyext coverage for PyLong_FromUnsignedLong(0), PyLong_FromUnsignedLong(1), and PyLong_FromUnsignedLong(ULONG_MAX).

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-003157.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSsize_t passed: 3 tests, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-003700.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSsize_t passed: 3 tests, OK (mxbuild/buildlog-20260506-004023.html).

Benchmarks: temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-unsigned-long.py and removed it before committing. Before each measured run, vmstat 5 13 observed the machine for about one minute; after the initial historical line the system stayed around 99-100% idle for current, baseline, and clean-baseline runs, and ps showed no active build/test CPU-heavy process. Command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-unsigned-long.py <iterations> <mode>, with modes 0=small, 1=ULONG_MAX, 2=mixed.

Benchmark results: mixed mode, 10,000,000 iterations: baseline median 7.462s (best 7.424s, worst 7.556s), current median 6.768s (best 6.573s, worst 6.841s), about 1.10x faster. Small-only mode, 100,000,000 iterations: baseline median 5.524s (best 5.476s, worst 5.626s), current median 0.137s (best 0.134s, worst 0.144s), about 40.35x faster. ULONG_MAX-only mode, 10,000,000 iterations: baseline median 6.876s (best 6.791s, worst 7.039s), current median 6.567s (best 6.503s, worst 6.689s), about 1.05x faster.
Enable the public C PyLong_FromUnsignedLongLong symbol and register PyLong_FromUnsignedLongLong as a CImpl entry point. The implementation uses the shared unsigned tagged-int fast path for small values and a private GraalPyPrivate_Long_FromUnsignedLongLong static C API helper for unsigned 64-bit values that need a multi-digit Python int. PyLong_FromSize_t remains Java-direct for its separate TODO.

Rename the previous unsigned-long private fallback helper to the unsigned-long-long helper so PyLong_FromUnsignedLong also routes large values through a 64-bit unsigned fallback without truncation on platforms where unsigned long is narrower than unsigned long long.

Add cpyext coverage for PyLong_FromUnsignedLongLong(0), PyLong_FromUnsignedLongLong(1), and PyLong_FromUnsignedLongLong(ULLONG_MAX).

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-004449.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLongLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t passed: 3 tests, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-004955.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLongLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t passed: 3 tests, OK (mxbuild/buildlog-20260506-005318.html).

Benchmarks: temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-unsigned-long-long.py and removed it before committing. Before each measured run, vmstat 5 13 observed the machine for about one minute; after the initial historical line the system stayed around 98-100% idle for current and 99-100% idle for baseline, and ps showed no active build/test CPU-heavy process. Command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-unsigned-long-long.py <iterations> <mode>, with modes 0=small, 1=ULLONG_MAX, 2=mixed.

Benchmark results: mixed mode, 10,000,000 iterations: baseline median 7.548s (best 7.441s, worst 7.600s), current median 6.484s (best 6.419s, worst 6.652s), about 1.16x faster. Small-only mode, 100,000,000 iterations: baseline median 5.405s (best 5.342s, worst 5.431s), current median 0.135s (best 0.133s, worst 0.141s), about 39.96x faster. ULLONG_MAX-only mode, 10,000,000 iterations: baseline median 6.561s (best 6.509s, worst 6.674s), current median 6.413s (best 6.248s, worst 6.445s), about 1.02x faster.
Enable the public C PyLong_FromSize_t symbol and register PyLong_FromSize_t as a CImpl entry point. Remove the Java direct PyLong_FromSize_t builtin class. The C path uses the shared unsigned tagged-int fast path and the existing GraalPyPrivate_Long_FromUnsignedLongLong fallback for size_t values requiring a multi-digit Python int.

Add cpyext coverage for PyLong_FromSize_t(0), PyLong_FromSize_t(1), and PyLong_FromSize_t((size_t)-1).

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-011818.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLongLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t passed: 3 tests, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-012328.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromUnsignedLongLong graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromSize_t passed: 3 tests, OK (mxbuild/buildlog-20260506-012653.html).

Benchmarks: temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-size-t.py and removed it before committing. Before each measured run, vmstat 5 13 observed the machine for about one minute; after the initial historical line the system stayed around 99-100% idle for current and baseline, and ps showed no active build/test CPU-heavy process. Command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-size-t.py <iterations> <mode>, with modes 0=small, 1=(size_t)-1, 2=mixed.

Benchmark results: mixed mode, 10,000,000 iterations: baseline median 7.259s (best 7.164s, worst 7.455s), current median 6.316s (best 6.263s, worst 6.437s), about 1.15x faster. Small-only mode, 100,000,000 iterations: baseline median 5.293s (best 5.152s, worst 5.361s), current median 0.133s (best 0.131s, worst 0.138s), about 39.80x faster. (size_t)-1-only mode, 10,000,000 iterations: baseline median 6.909s (best 6.835s, worst 6.930s), current median 6.286s (best 6.176s, worst 6.346s), about 1.10x faster.
Enable the public C PyLong_FromDouble symbol and register it as CImpl. The C path handles finite double values fitting in long by calling PyLong_FromLong((long)dval), and falls back to a private static Java helper for NaN, infinities, and large finite values because the CPython multi-digit path uses _PyLong_New, which is not available through this route.

Add cpyext coverage for PyLong_FromDouble(1.0e100) to exercise the large finite fallback path.

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-014930.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromDouble passed: 1 test, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-015441.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromDouble passed: 1 test, OK (mxbuild/buildlog-20260506-015807.html). git diff --check passed.

Temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-double.py covering integral, non-integral, large finite fallback, and mixed loops; removed the temporary benchmark before committing.

Quietness checks before benchmark: vmstat 5 13 over about one minute showed 99-100% idle after the initial historical line; ps showed no active build/test CPU-heavy process. After stopping an oversized exploratory large-fallback run, repeated vmstat 5 13 showed 99-100% idle again before the final benchmark runs. Emacs appeared with a lifetime CPU average, but vmstat showed no active CPU pressure during the observation windows.

Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-from-double.py <iterations> <mode>. Modes: 0 = integral 42.0, 1 = non-integral 42.75, 2 = large finite 1.0e100, 3 = mixed.

Current build used /tmp/graalpy-pylong-from-double-current-20260506-0200/bin/graalpy; clean baseline used /home/tim/dev/graalpython/.agent-shell/worktrees/gr-49498/graalpython-pylong-double-baseline/mxbuild/linux-amd64/GRAALPY_NATIVE_STANDALONE/bin/graalpy built from HEAD before this item (mxbuild/buildlog-20260506-020317.html).

Benchmark results: Integral, 100,000,000 iterations, mode 0: baseline median 5.439s (best 5.344s, worst 5.584s); current median 0.213s (best 0.210s, worst 0.218s), about 25.51x faster. Non-integral, 100,000,000 iterations, mode 1: baseline median 5.498s (best 5.430s, worst 5.630s); current median 0.213s (best 0.209s, worst 0.223s), about 25.83x faster. Large finite fallback, 100,000 iterations, mode 2: baseline median 0.069s (best 0.066s, worst 0.075s); current median 0.066s (best 0.053s, worst 0.071s), about 1.03x faster. Mixed, 100,000 iterations, mode 3: baseline median 0.081s (best 0.073s, worst 0.090s); current median 0.070s (best 0.057s, worst 0.072s), about 1.16x faster.

Conclusion: moving PyLong_FromDouble to CImpl with a C fast path for values fitting in long improves the native no-compilation benchmark while preserving the Java fallback behavior for large finite double values.
Enable the public C _PyLong_Sign symbol and register it as CImpl. Remove the Java direct _PyLong_Sign builtin class. The C implementation handles GraalPy tagged-int handles directly and computes non-tagged long signs from a single GraalPyPrivate_Long_lv_tag read.

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-024013.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test__PyLong_Sign passed: 1 test, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-024520.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test__PyLong_Sign passed: 1 test, OK (mxbuild/buildlog-20260506-024844.html). git diff --check passed.

Temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-sign.py covering negative, zero, positive, large multi-digit, and mixed loops; removed the temporary benchmark before committing.

Quietness checks before benchmark: vmstat 5 13 over about one minute showed 99-100% idle after the initial historical line; ps showed no active build/test CPU-heavy process. After stopping an oversized exploratory large-mode run, repeated vmstat 5 13 showed 99-100% idle again. After the final native rebuild and focused SVM test, a final vmstat 5 13 again showed 99-100% idle before current measurements. Emacs appeared with a lifetime CPU average, but vmstat showed no active CPU pressure during the observation windows.

Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-sign.py <iterations> <mode>. Modes: 0 = negative, 1 = zero, 2 = positive, 3 = large multi-digit, 4 = mixed negative + zero + positive + large.

Current build used /tmp/graalpy-pylong-sign-current-20260506-0248/bin/graalpy; clean baseline used /home/tim/dev/graalpython/.agent-shell/worktrees/gr-49498/graalpython-pylong-sign-baseline/mxbuild/linux-amd64/GRAALPY_NATIVE_STANDALONE/bin/graalpy built from HEAD before this item (mxbuild/buildlog-20260506-022927.html).

Benchmark results: Negative tagged int, 100,000,000 iterations, mode 0: baseline median 4.508s (best 4.436s, worst 4.553s); current median 0.140s (best 0.139s, worst 0.147s), about 32.11x faster. Zero tagged int, 100,000,000 iterations, mode 1: baseline median 4.347s (best 4.263s, worst 4.393s); current median 0.140s (best 0.139s, worst 0.143s), about 31.01x faster. Positive tagged int, 100,000,000 iterations, mode 2: baseline median 4.439s (best 4.398s, worst 4.530s); current median 0.142s (best 0.141s, worst 0.146s), about 31.22x faster. Large multi-digit int, 1,000,000 iterations, mode 3: baseline median 0.045s (best 0.044s, worst 0.050s); current median 0.051s (best 0.049s, worst 0.054s), about 0.89x as fast. Mixed, 1,000,000 iterations, mode 4: baseline median 0.176s (best 0.174s, worst 0.180s); current median 0.058s (best 0.056s, worst 0.061s), about 3.01x faster.

Conclusion: moving _PyLong_Sign to CImpl with a tagged-int fast path improves the common tagged-int and mixed native no-compilation benchmarks substantially. The isolated large multi-digit path is slightly slower than the Java direct baseline, but the mixed benchmark still improves because the tagged-int cases dominate this low-level API's common use.
Enable the public C _PyLong_NumBits symbol and register it as CImpl. Remove the Java direct _PyLong_NumBits builtin class. The C implementation handles GraalPy tagged-int handles directly and falls back to a private static Java helper for non-tagged longs; the pure CPython digit-array path was unsafe for managed GraalPy ints and crashed in the focused JVM cpyext test.

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-025834.html). mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test__PyLong_NumBits passed: 1 test, OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-030344.html). JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true mx graalpytest --svm graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test__PyLong_NumBits passed: 1 test, OK (mxbuild/buildlog-20260506-030707.html). git diff --check passed.

Temporarily added graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-numbits.py covering small tagged int, large multi-digit int, negative int, and mixed loops; removed the temporary benchmark before committing.

Quietness check before benchmark: vmstat 5 13 over about one minute showed 99-100% idle after the initial historical line; ps showed no active build/test CPU-heavy process. Emacs appeared with a lifetime CPU average, but vmstat showed no active CPU pressure during the observation window.

Benchmark command shape: <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-numbits.py <iterations> <mode>. Modes: 0 = small tagged int, 1 = large multi-digit int, 2 = negative int, 3 = mixed small + large + negative.

Current build used /tmp/graalpy-pylong-numbits-current-20260506-0307/bin/graalpy; clean baseline used /home/tim/dev/graalpython/.agent-shell/worktrees/gr-49498/graalpython-pylong-numbits-baseline/mxbuild/linux-amd64/GRAALPY_NATIVE_STANDALONE/bin/graalpy built from HEAD before this item (mxbuild/buildlog-20260506-031214.html).

Benchmark results: Small tagged int, 100,000,000 iterations, mode 0: baseline median 4.598s (best 4.539s, worst 4.698s); current median 0.142s (best 0.141s, worst 0.152s), about 32.44x faster. Large multi-digit int, 1,000,000 iterations, mode 1: baseline median 0.050s (best 0.048s, worst 0.054s); current median 0.020s (best 0.020s, worst 0.021s), about 2.48x faster. Negative int, 1,000,000 iterations, mode 2: baseline median 0.054s (best 0.051s, worst 0.059s); current median 0.020s (best 0.020s, worst 0.021s), about 2.65x faster. Mixed, 1,000,000 iterations, mode 3: baseline median 0.197s (best 0.195s, worst 0.202s); current median 0.042s (best 0.041s, worst 0.044s), about 4.69x faster.

Conclusion: moving _PyLong_NumBits to CImpl with a tagged-int C fast path and Java fallback for non-tagged longs improves all measured native no-compilation benchmark modes while preserving managed-int safety.
Move PyLong_AsVoidPtr from the Java-direct C API builtin to a CImpl entry in CApiFunction. Enable the public C symbol in longobject.c with a tagged-int C fast path for common small positive and negative handles, and keep non-tagged behavior on the private Java fallback GraalPyPrivate_Long_AsVoidPtr. The fallback preserves unsigned pointer-sized positive values such as UINTPTR_MAX while still raising overflow beyond the pointer range.

Add cpyext coverage for PyLong_AsVoidPtr round-tripping 0, 42, -1, 0xffffffff, 0xffffffffffffffff, and 0x10000000000000000.

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-034842.html). Focused JVM tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_AsVoidPtr graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_AsVoidPtrAllocated graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyLong_FromAndToVoidPtrAllocated, 3 tests OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-035346.html; native focused-test rebuild mxbuild/buildlog-20260506-035709.html). Focused native tests passed with GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true, 3 tests OK. mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/ passed: 2811 tests in 700.20s, OK (passed=2792, skipped=19). git diff --check passed.

Temporary benchmark c-pylong-asvoidptr.py was used and removed before commit. Benchmarks used <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-asvoidptr.py <iterations> <mode>. Modes: 0 small positive tagged int; 1 signed pointer-sized positive value, UINTPTR_MAX >> 1; 2 negative tagged int; 3 overflow beyond pointer size; 4 mixed small + pointer-sized + negative. Before benchmarking, vmstat 5 13 showed 99-100% idle after the initial historical sample and ps showed no active build/test CPU-heavy process.

Benchmark results: mode 0, 100000000 iterations: baseline median 4.489s (best 4.446s, worst 4.568s), current median 0.126s (best 0.121s, worst 0.128s), about 35.64x faster. Mode 1, 10000000 iterations: baseline median 0.766s (best 0.757s, worst 0.781s), current median 0.764s (best 0.740s, worst 0.800s), effectively flat/slightly faster. Mode 2, 100000000 iterations: baseline median 4.362s (best 4.290s, worst 4.503s), current median 0.127s (best 0.125s, worst 0.133s), about 34.42x faster. Mode 3, 1000000 iterations: baseline median 0.810s (best 0.780s, worst 0.824s), current median 0.839s (best 0.820s, worst 0.853s), about 0.97x as fast. Mode 4, 10000000 iterations: baseline median 1.690s (best 1.666s, worst 1.716s), current median 0.833s (best 0.816s, worst 0.849s), about 2.03x faster.

Conclusion: moving PyLong_AsVoidPtr to CImpl with a tagged-int C fast path and Java fallback for non-tagged values improves common tagged-int and mixed native no-compilation workloads while preserving pointer-sized unsigned correctness. The isolated overflow path is slightly slower, but the mixed benchmark improves substantially and the large pointer-sized path remains baseline-level.
Move PyUnstable_Long_IsCompact from the Java-direct C API builtin to a CImpl entry in CApiFunction. Enable the public C symbol in the active GraalPy section of longobject.c. The active implementation reads GraalPyPrivate_Long_lv_tag(op) directly and applies the compact-tag predicate, because in GraalPy headers _PyLong_IsCompact macro-routes back to the public symbol.

Existing cpyext coverage for compact 0, -1, 1, and an obviously non-compact large int continues to pass.

Verification: mx python-jvm passed (mxbuild/buildlog-20260506-041616.html). Focused JVM tests passed: mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyUnstable_Long_IsCompact graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_long.py::tests.cpyext.test_long.TestPyLong.test_PyUnstable_Long_CompactValue, 2 tests OK. JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest LATEST_JAVA_HOME=/home/tim/.mx/jdks/labsjdk-ce-latest mx python-svm passed (mxbuild/buildlog-20260506-042143.html; native focused-test rebuild mxbuild/buildlog-20260506-042507.html). Focused native tests passed with GRAALPYTEST_ALLOW_NO_JAVA_ASSERTIONS=true, 2 tests OK. mx graalpytest graalpython/com.oracle.graal.python.test/src/tests/ passed: 2811 tests in 694.82s, OK (passed=2792, skipped=19). git diff --check passed.

Temporary benchmark c-pylong-iscompact.py was used and removed before commit. Benchmarks used <graalpy> --experimental-options --engine.Compilation=false graalpython/com.oracle.graal.python.benchmarks/python/harness.py -r 3 -i 9 graalpython/com.oracle.graal.python.benchmarks/python/micro/c-pylong-iscompact.py <iterations> <mode>. Modes: 0 compact positive tagged int; 1 non-compact large int; 2 compact negative tagged int; 3 mixed compact positive + non-compact large + compact negative. Before benchmarking, vmstat 5 13 showed 99-100% idle after the initial historical sample and ps showed no active build/test CPU-heavy process.

Benchmark results: mode 0, 100000000 iterations: baseline median 4.699s (best 4.586s, worst 4.728s), current median 0.175s (best 0.171s, worst 0.176s), about 26.80x faster. Mode 1, 10000000 iterations: baseline median 0.533s (best 0.517s, worst 0.540s), current median 0.517s (best 0.507s, worst 0.520s), about 1.03x faster. Mode 2, 100000000 iterations: baseline median 4.593s (best 4.553s, worst 4.690s), current median 0.175s (best 0.171s, worst 0.184s), about 26.25x faster. Mode 3, 10000000 iterations: baseline median 1.425s (best 1.409s, worst 1.440s), current median 0.570s (best 0.553s, worst 0.584s), about 2.50x faster.

Conclusion: moving PyUnstable_Long_IsCompact to CImpl improves compact tagged-int checks dramatically, keeps non-compact large-int checks slightly faster, and improves the mixed native no-compilation benchmark by about 2.50x.
@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants