diff --git a/.agents/skills/rota-bench-regression-analysis/SKILL.md b/.agents/skills/rota-bench-regression-analysis/SKILL.md
index ee5449ace3..5779ea32dc 100644
--- a/.agents/skills/rota-bench-regression-analysis/SKILL.md
+++ b/.agents/skills/rota-bench-regression-analysis/SKILL.md
@@ -78,6 +78,7 @@ git diff --stat GOOD..BAD
- In the attributed section, use this header format: `abcd1234efgh | author@oracle.com | Full subject`
- Unattributed changes that look plausible go to "to bisect", flaky ones go to "to watch"
- In the "to bisect" section, add an invocation (don't execute yet) of `scripts/bisect_benchmark_regression.py` that can bisect it (use unabbreviated commits in this case)
+- The positional benchmark name identifies the result to compare. If the harness runs that result through a differently named parent or group, pass the runnable name with `--benchmark-selector`. For example, use result `pyperformance-suite.scimark_fft` with `--benchmark-selector scimark`, because pyperformance runs the `scimark` group and reports `scimark_fft` separately.
- In the "to watch" section, say whether the item looks flaky, or likely the same cause as another attributed item.
- Do not abbreviate commit subjects.
- Keep author emails.
diff --git a/abi/abi-graalpy253.xml b/abi/abi-graalpy253.xml
new file mode 100644
index 0000000000..bd238a0633
--- /dev/null
+++ b/abi/abi-graalpy253.xml
@@ -0,0 +1,14963 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ci/python-gate.libsonnet b/ci/python-gate.libsonnet
index f7ab83145c..14e8870953 100644
--- a/ci/python-gate.libsonnet
+++ b/ci/python-gate.libsonnet
@@ -517,6 +517,8 @@
$.overlay_imports.BUILDBOT_COMMIT_SERVICE + '?repoName=graal&target=weekly&before-ts=${MAIN_COMMIT_TS}']],
["git", "clone", $.overlay_imports.GRAAL_ENTERPRISE_GIT, "../graal-enterprise"],
['git', '-C', '../graal', 'checkout', '${GRAAL_COMMIT}'],
+ ['mx', '-p', '../graal', 'fetch-jdk', '-A', 'labsjdk-ce-latest'],
+ ['set-export', 'JAVA_HOME', ['mx', '-p', '../graal', 'get-jdk-path', 'labsjdk-ce-latest']],
// NOTE: this will checkout older graalpy. We need to live with that to ensure consistency with graal
['mx', '-p', '../graal/vm', '--dynamicimports', 'graalpython', 'sforceimports'],
// NOTE: jvm-only, so not need to handle substratevm-enterprise-gcs
diff --git a/graalpython/com.oracle.graal.python.cext/CMakeLists.txt b/graalpython/com.oracle.graal.python.cext/CMakeLists.txt
index 8fe18afaca..04196a6e16 100644
--- a/graalpython/com.oracle.graal.python.cext/CMakeLists.txt
+++ b/graalpython/com.oracle.graal.python.cext/CMakeLists.txt
@@ -165,6 +165,7 @@ set(SRC_FILES ${CAPI_SRC}/codecs.c ${CAPI_SRC}/compile.c ${CAPI_SRC}/thread.c
${CAPI_SRC}/genobject.c ${CAPI_SRC}/methodobject.c ${CAPI_SRC}/boolobject.c ${CAPI_SRC}/pylifecycle.c
${CAPI_SRC}/errors.c ${CAPI_SRC}/signals.c ${CAPI_SRC}/datetime.c ${CAPI_SRC}/call.c
${CAPI_SRC}/getargs.c ${CAPI_SRC}/tracemalloc.c ${CAPI_SRC}/initconfig.c ${CAPI_SRC}/graalpy_stacktrace.c
+ ${CAPI_SRC}/graalpyarray.c
${CAPI_SRC}/lock.c ${CAPI_SRC}/parking_lot.c
)
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/cellobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/cellobject.h
index 68f012f62b..d49313186b 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/cellobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/cellobject.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, 2024, Oracle and/or its affiliates.
+/* Copyright (c) 2018, 2026, Oracle and/or its affiliates.
* Copyright (C) 1996-2020 Python Software Foundation
*
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -26,19 +26,19 @@ PyAPI_FUNC(PyObject *) PyCell_New(PyObject *);
PyAPI_FUNC(PyObject *) PyCell_Get(PyObject *);
PyAPI_FUNC(int) PyCell_Set(PyObject *, PyObject *);
+/* GraalPy public API functions replacing direct PyCellObject field access. */
+PyAPI_FUNC(PyObject *) GraalPyCell_GET(PyObject *op);
+PyAPI_FUNC(void) GraalPyCell_SET(PyObject *op, PyObject *value);
+
static inline PyObject* PyCell_GET(PyObject *op) {
- PyCellObject *cell;
assert(PyCell_Check(op));
- cell = _Py_CAST(PyCellObject*, op);
- return cell->ob_ref;
+ return GraalPyCell_GET(op);
}
#define PyCell_GET(op) PyCell_GET(_PyObject_CAST(op))
static inline void PyCell_SET(PyObject *op, PyObject *value) {
- PyCellObject *cell;
assert(PyCell_Check(op));
- cell = _Py_CAST(PyCellObject*, op);
- cell->ob_ref = value;
+ GraalPyCell_SET(op, value);
}
#define PyCell_SET(op, value) PyCell_SET(_PyObject_CAST(op), (value))
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/code.h b/graalpython/com.oracle.graal.python.cext/include/cpython/code.h
index f529fad331..4a57e7774d 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/code.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/code.h
@@ -186,14 +186,18 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
#define PyCode_Check(op) Py_IS_TYPE((op), &PyCode_Type)
+/* GraalPy public API functions replacing direct PyCodeObject field access. */
+PyAPI_FUNC(Py_ssize_t) GraalPyCode_GetNumFree(PyCodeObject *op);
+PyAPI_FUNC(int) GraalPyCode_GetFirstFree(PyCodeObject *op);
+
static inline Py_ssize_t PyCode_GetNumFree(PyCodeObject *op) {
assert(PyCode_Check(op));
- return op->co_nfreevars;
+ return GraalPyCode_GetNumFree(op);
}
static inline int PyUnstable_Code_GetFirstFree(PyCodeObject *op) {
assert(PyCode_Check(op));
- return op->co_nlocalsplus - op->co_nfreevars;
+ return GraalPyCode_GetFirstFree(op);
}
Py_DEPRECATED(3.13) static inline int PyCode_GetFirstFree(PyCodeObject *op) {
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/dictobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/dictobject.h
index 331fab9bd3..1aac6e296e 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/dictobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/dictobject.h
@@ -56,18 +56,15 @@ PyAPI_FUNC(PyObject *) PyDict_SetDefault(
// 1 if `key` was present and `default_value` was not inserted
PyAPI_FUNC(int) PyDict_SetDefaultRef(PyObject *mp, PyObject *key, PyObject *default_value, PyObject **result);
+/* GraalPy public API function replacing direct PyDictObject field access. */
+PyAPI_FUNC(Py_ssize_t) GraalPyDict_GET_SIZE(PyObject *op);
+
/* Get the number of items of a dictionary. */
static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) {
- PyDictObject *mp;
assert(PyDict_Check(op));
- mp = _Py_CAST(PyDictObject*, op);
-#ifdef Py_GIL_DISABLED
- return _Py_atomic_load_ssize_relaxed(&mp->ma_used);
-#else
- return mp->ma_used;
-#endif
+ return GraalPyDict_GET_SIZE(op);
}
-#define PyDict_GET_SIZE(mp) (assert(PyDict_Check(mp)),PyObject_Size((PyObject*) mp))
+#define PyDict_GET_SIZE(op) PyDict_GET_SIZE(_PyObject_CAST(op))
PyAPI_FUNC(int) PyDict_ContainsString(PyObject *mp, const char *key);
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/funcobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/funcobject.h
index 50f863a887..9f235c6cf7 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/funcobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/funcobject.h
@@ -89,40 +89,50 @@ PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *);
#define _PyFunction_CAST(func) \
(assert(PyFunction_Check(func)), _Py_CAST(PyFunctionObject*, func))
+/* GraalPy public API functions replacing direct PyFunctionObject field access.
+ Return borrowed references. */
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_CODE(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_GLOBALS(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_MODULE(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_DEFAULTS(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_KW_DEFAULTS(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_CLOSURE(PyObject *func);
+PyAPI_FUNC(PyObject *) GraalPyFunction_GET_ANNOTATIONS(PyObject *func);
+
/* Static inline functions for direct access to these values.
Type checks are *not* done, so use with care. */
static inline PyObject* PyFunction_GET_CODE(PyObject *func) {
- return _PyFunction_CAST(func)->func_code;
+ return GraalPyFunction_GET_CODE(func);
}
#define PyFunction_GET_CODE(func) PyFunction_GET_CODE(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_GLOBALS(PyObject *func) {
- return _PyFunction_CAST(func)->func_globals;
+ return GraalPyFunction_GET_GLOBALS(func);
}
#define PyFunction_GET_GLOBALS(func) PyFunction_GET_GLOBALS(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_MODULE(PyObject *func) {
- return _PyFunction_CAST(func)->func_module;
+ return GraalPyFunction_GET_MODULE(func);
}
#define PyFunction_GET_MODULE(func) PyFunction_GET_MODULE(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_DEFAULTS(PyObject *func) {
- return _PyFunction_CAST(func)->func_defaults;
+ return GraalPyFunction_GET_DEFAULTS(func);
}
#define PyFunction_GET_DEFAULTS(func) PyFunction_GET_DEFAULTS(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_KW_DEFAULTS(PyObject *func) {
- return _PyFunction_CAST(func)->func_kwdefaults;
+ return GraalPyFunction_GET_KW_DEFAULTS(func);
}
#define PyFunction_GET_KW_DEFAULTS(func) PyFunction_GET_KW_DEFAULTS(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_CLOSURE(PyObject *func) {
- return _PyFunction_CAST(func)->func_closure;
+ return GraalPyFunction_GET_CLOSURE(func);
}
#define PyFunction_GET_CLOSURE(func) PyFunction_GET_CLOSURE(_PyObject_CAST(func))
static inline PyObject* PyFunction_GET_ANNOTATIONS(PyObject *func) {
- return _PyFunction_CAST(func)->func_annotations;
+ return GraalPyFunction_GET_ANNOTATIONS(func);
}
#define PyFunction_GET_ANNOTATIONS(func) PyFunction_GET_ANNOTATIONS(_PyObject_CAST(func))
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/memoryobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/memoryobject.h
index 8ea700350d..3ef6ad88d3 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/memoryobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/memoryobject.h
@@ -42,14 +42,18 @@ typedef struct {
#define _PyMemoryView_CAST(op) _Py_CAST(PyMemoryViewObject*, op)
+/* GraalPy public API functions replacing direct PyMemoryViewObject field access. */
+PyAPI_FUNC(Py_buffer *) GraalPyMemoryView_GET_BUFFER(PyObject *op);
+PyAPI_FUNC(PyObject *) GraalPyMemoryView_GET_BASE(PyObject *op);
+
/* Get a pointer to the memoryview's private copy of the exporter's buffer. */
static inline Py_buffer* PyMemoryView_GET_BUFFER(PyObject *op) {
- return (&_PyMemoryView_CAST(op)->view);
+ return GraalPyMemoryView_GET_BUFFER(op);
}
#define PyMemoryView_GET_BUFFER(op) PyMemoryView_GET_BUFFER(_PyObject_CAST(op))
/* Get a pointer to the exporting object (this may be NULL!). */
static inline PyObject* PyMemoryView_GET_BASE(PyObject *op) {
- return _PyMemoryView_CAST(op)->view.obj;
+ return GraalPyMemoryView_GET_BASE(op);
}
#define PyMemoryView_GET_BASE(op) PyMemoryView_GET_BASE(_PyObject_CAST(op))
diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h
index 62ab105485..85f89e8a92 100644
--- a/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h
@@ -39,9 +39,8 @@ PyAPI_FUNC(void) GraalPyTuple_SET_ITEM(PyObject*, Py_ssize_t, PyObject*);
/* Function *only* to be used to fill in brand new tuples */
static inline void
PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
- PyTupleObject *tuple = _PyTuple_CAST(op);
assert(0 <= index);
- assert(index < Py_SIZE(tuple));
+ assert(index < Py_SIZE(_PyTuple_CAST(op)));
GraalPyTuple_SET_ITEM(op, index, value);
}
#define PyTuple_SET_ITEM(op, index, value) \
diff --git a/graalpython/com.oracle.graal.python.cext/include/listobject.h b/graalpython/com.oracle.graal.python.cext/include/listobject.h
index 5d8510bc0c..8a0280eb21 100644
--- a/graalpython/com.oracle.graal.python.cext/include/listobject.h
+++ b/graalpython/com.oracle.graal.python.cext/include/listobject.h
@@ -57,6 +57,17 @@ PyAPI_FUNC(int) GraalPyArray_Resize(PyObject* array, Py_ssize_t new_size);
*/
PyAPI_FUNC(char*) GraalPyArray_Data(PyObject* array);
+typedef struct GraalPyArray_Descriptor {
+ char typecode;
+ int itemsize;
+} GraalPyArray_Descriptor;
+
+/*
+ * GraalPy public API used by Cython's array module. Available since GraalPy 25.3.4.
+ */
+PyAPI_FUNC(GraalPyArray_Descriptor*) GraalPyArray_GetDescriptor(PyObject* array);
+PyAPI_FUNC(PyObject*) GraalPyArray_New(PyObject* type, Py_ssize_t size, GraalPyArray_Descriptor* descriptor);
+
#ifndef Py_LIMITED_API
# define Py_CPYTHON_LISTOBJECT_H
# include "cpython/listobject.h"
diff --git a/graalpython/com.oracle.graal.python.cext/include/pylifecycle.h b/graalpython/com.oracle.graal.python.cext/include/pylifecycle.h
index 5e4f47a1a5..75428e64c7 100644
--- a/graalpython/com.oracle.graal.python.cext/include/pylifecycle.h
+++ b/graalpython/com.oracle.graal.python.cext/include/pylifecycle.h
@@ -73,6 +73,9 @@ PyAPI_DATA(const unsigned long) Py_Version;
PyAPI_FUNC(int) Py_IsFinalizing(void);
#endif
+// GraalPy change: compatibility alias for pybind11
+PyAPI_FUNC(int) _Py_IsFinalizing(void);
+
#ifndef Py_LIMITED_API
# define Py_CPYTHON_PYLIFECYCLE_H
# include "cpython/pylifecycle.h"
diff --git a/graalpython/com.oracle.graal.python.cext/src/capi.h b/graalpython/com.oracle.graal.python.cext/src/capi.h
index bada348ba4..3fcfa909e6 100644
--- a/graalpython/com.oracle.graal.python.cext/src/capi.h
+++ b/graalpython/com.oracle.graal.python.cext/src/capi.h
@@ -323,18 +323,36 @@ PY_TRUFFLE_TYPE_LOCAL(Arraytype, "array", &
PY_TRUFFLE_TYPE_LOCAL(mmap_object_type, "mmap.mmap", &PyType_Type, 0) \
PY_TRUFFLE_TYPE(PyArrayIter_Type, "arrayiterator", &PyType_Type, sizeof(arrayiterobject)) \
PY_TRUFFLE_TYPE(PyAsyncGen_Type, "async_generator", &PyType_Type, sizeof(PyAsyncGenObject)) \
+PY_TRUFFLE_TYPE(_PyAsyncGenASend_Type, "async_generator_asend", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(_PyAsyncGenAThrow_Type, "async_generator_athrow", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(_PyAsyncGenWrappedValue_Type, "async_generator_wrapped_value", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE_WITH_ITEMSIZE(PyLong_Type, "int", &PyType_Type, offsetof(PyLongObject, long_value.ob_digit), sizeof(PyObject *)) \
PY_TRUFFLE_TYPE(PyBool_Type, "bool", &PyType_Type, sizeof(struct _longobject)) \
PY_TRUFFLE_TYPE(PyByteArray_Type, "bytearray", &PyType_Type, sizeof(PyByteArrayObject)) \
PY_TRUFFLE_TYPE_WITH_ITEMSIZE(PyBytes_Type, "bytes", &PyType_Type, PyBytesObject_SIZE, sizeof(char)) \
PY_TRUFFLE_TYPE_WITH_ALLOC(PyCapsule_Type, "PyCapsule", &PyType_Type, sizeof(PyCapsule), PyType_GenericAlloc, capsule_dealloc, PyObject_Del) \
+PY_TRUFFLE_TYPE(PyCallIter_Type, "callable_iterator", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyCell_Type, "cell", &PyType_Type, sizeof(PyCellObject)) \
PY_TRUFFLE_TYPE(PyCMethod_Type, "builtin_method", &PyCFunction_Type, sizeof(PyCFunctionObject)) \
+PY_TRUFFLE_TYPE(PyClassMethod_Type, "classmethod", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyClassMethodDescr_Type, "classmethod_descriptor", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyCode_Type, "code", &PyType_Type, sizeof(PyTypeObject)) \
+PY_TRUFFLE_TYPE(PyCmpWrapper_Type, "KeyWrapper", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyComplex_Type, "complex", &PyType_Type, sizeof(PyComplexObject)) \
+PY_TRUFFLE_TYPE(PyContext_Type, "Context", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyContextToken_Type, "Token", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyContextVar_Type, "ContextVar", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(_PyCoroWrapper_Type, "coroutine_wrapper", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE_EXTERN(PyDict_Type, "dict" ) \
+PY_TRUFFLE_TYPE(PyDictIterItem_Type, "dict_itemiterator", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyDictIterKey_Type, "dict_keyiterator", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyDictIterValue_Type, "dict_valueiterator", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyDictItems_Type, "dict_items", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyDictKeys_Type, "dict_keys", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyDictProxy_Type, "mappingproxy", &PyType_Type, sizeof(mappingproxyobject)) \
+PY_TRUFFLE_TYPE(PyDictValues_Type, "dict_values", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyEllipsis_Type, "ellipsis", &PyType_Type, 0) \
+PY_TRUFFLE_TYPE(PyFilter_Type, "filter", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyFloat_Type, "float", &PyType_Type, sizeof(PyFloatObject)) \
PY_TRUFFLE_TYPE_WITH_ITEMSIZE(PyFrame_Type, "frame", &PyType_Type, sizeof(PyTypeObject), sizeof(PyObject *)) \
PY_TRUFFLE_TYPE(PyFrozenSet_Type, "frozenset", &PyType_Type, sizeof(PySetObject)) \
@@ -347,9 +365,15 @@ PY_TRUFFLE_TYPE(PyMap_Type, "map", &
PY_TRUFFLE_TYPE(PyMemberDescr_Type, "member_descriptor", &PyType_Type, sizeof(PyMemberDescrObject)) \
PY_TRUFFLE_TYPE_WITH_ITEMSIZE(PyMemoryView_Type, "memoryview", &PyType_Type, offsetof(PyMemoryViewObject, ob_array), sizeof(Py_ssize_t)) \
PY_TRUFFLE_TYPE(PyMethod_Type, "method", &PyType_Type, sizeof(PyMethodObject)) \
+PY_TRUFFLE_TYPE(_PyMethodWrapper_Type, "method-wrapper", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyMethodDescr_Type, "method_descriptor", &PyType_Type, sizeof(PyMethodDescrObject)) \
PY_TRUFFLE_TYPE_EXTERN(PyModule_Type, "module" ) \
PY_TRUFFLE_TYPE(PyModuleDef_Type, "moduledef", &PyType_Type, sizeof(struct PyModuleDef)) \
+PY_TRUFFLE_TYPE(PyODict_Type, "OrderedDict", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyODictItems_Type, "odict_items", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyODictIter_Type, "odict_iterator", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyODictKeys_Type, "odict_keys", &PyType_Type, sizeof(PyObject)) \
+PY_TRUFFLE_TYPE(PyODictValues_Type, "odict_values", &PyType_Type, sizeof(PyObject)) \
PY_TRUFFLE_TYPE(PyProperty_Type, "property", &PyType_Type, sizeof(propertyobject)) \
PY_TRUFFLE_TYPE(PyRange_Type, "range", &PyType_Type, sizeof(rangeobject)) \
PY_TRUFFLE_TYPE(PySet_Type, "set", &PyType_Type, sizeof(PySetObject)) \
@@ -370,11 +394,8 @@ PY_TRUFFLE_TYPE(PyCoro_Type, "coroutine", &
PY_TRUFFLE_TYPE(Py_GenericAliasType, "types.GenericAlias", &PyType_Type, sizeof(PyObject)) \
/* PyPickleBufferObject (PyObject_HEAD + Py_buffer + PyObject*) is defined within Objects/picklebufobject.c, so its not exposed. */ \
PY_TRUFFLE_TYPE(PyPickleBuffer_Type, "_pickle.PickleBuffer", &PyType_Type, sizeof(PyPickleBufferObject)) \
+/* GraalPy has no corresponding Python object types for these CPython implementation details. */ \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyAIterWrapper_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyAsyncGenASend_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyAsyncGenAThrow_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyAsyncGenWrappedValue_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyCoroWrapper_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyHamt_ArrayNode_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyHamt_BitmapNode_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyHamt_CollisionNode_Type) \
@@ -384,41 +405,21 @@ PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyHamtKeys_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyHamtValues_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyInterpreterID_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyManagedBuffer_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(_PyMethodWrapper_Type) \
+PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyNullImporter_Type) \
+PY_TRUFFLE_TYPE_UNIMPLEMENTED(PySortWrapper_Type) \
+PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyStdPrinter_Type) \
+PY_TRUFFLE_TYPE_UNIMPLEMENTED(PySTEntry_Type) \
+/* GraalPy represents these using shared iterator types rather than distinct Python types. */ \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyByteArrayIter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyBytesIter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyCallIter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyClassMethod_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyClassMethodDescr_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyCmpWrapper_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyContext_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyContextToken_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyContextVar_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictItems_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictIterItem_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictIterKey_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictIterValue_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictKeys_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictRevIterItem_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictRevIterKey_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictRevIterValue_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyDictValues_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyFilter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyListIter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyListRevIter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyLongRangeIter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyNullImporter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyODict_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyODictItems_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyODictIter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyODictKeys_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyODictValues_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyRangeIter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PySetIter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PySortWrapper_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyStaticMethod_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyStdPrinter_Type) \
-PY_TRUFFLE_TYPE_UNIMPLEMENTED(PySTEntry_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyTupleIter_Type) \
PY_TRUFFLE_TYPE_UNIMPLEMENTED(PyUnicodeIter_Type) \
diff --git a/graalpython/com.oracle.graal.python.cext/src/graalpyarray.c b/graalpython/com.oracle.graal.python.cext/src/graalpyarray.c
new file mode 100644
index 0000000000..15b11555fb
--- /dev/null
+++ b/graalpython/com.oracle.graal.python.cext/src/graalpyarray.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+#include "capi.h"
+
+#if PY_VERSION_HEX >= 0x030F0000
+_Static_assert(sizeof(((GraalPyArray_Descriptor *)0)->typecode) == 3,
+ "GraalPyArray_Descriptor.typecode must support multi-character Python 3.15 array typecodes");
+#endif
+
+#define GRAALPY_ARRAY_DESCRIPTOR(TYPECODE, TYPE) \
+ {TYPECODE, sizeof(TYPE)}
+
+static GraalPyArray_Descriptor array_descriptor_b = GRAALPY_ARRAY_DESCRIPTOR('b', signed char);
+static GraalPyArray_Descriptor array_descriptor_B = GRAALPY_ARRAY_DESCRIPTOR('B', unsigned char);
+static GraalPyArray_Descriptor array_descriptor_u = GRAALPY_ARRAY_DESCRIPTOR('u', Py_UCS4);
+static GraalPyArray_Descriptor array_descriptor_w = GRAALPY_ARRAY_DESCRIPTOR('w', Py_UCS4);
+static GraalPyArray_Descriptor array_descriptor_h = GRAALPY_ARRAY_DESCRIPTOR('h', short);
+static GraalPyArray_Descriptor array_descriptor_H = GRAALPY_ARRAY_DESCRIPTOR('H', unsigned short);
+static GraalPyArray_Descriptor array_descriptor_i = GRAALPY_ARRAY_DESCRIPTOR('i', int);
+static GraalPyArray_Descriptor array_descriptor_I = GRAALPY_ARRAY_DESCRIPTOR('I', unsigned int);
+static GraalPyArray_Descriptor array_descriptor_l = GRAALPY_ARRAY_DESCRIPTOR('l', long);
+static GraalPyArray_Descriptor array_descriptor_L = GRAALPY_ARRAY_DESCRIPTOR('L', unsigned long);
+static GraalPyArray_Descriptor array_descriptor_q = GRAALPY_ARRAY_DESCRIPTOR('q', long long);
+static GraalPyArray_Descriptor array_descriptor_Q = GRAALPY_ARRAY_DESCRIPTOR('Q', unsigned long long);
+static GraalPyArray_Descriptor array_descriptor_f = GRAALPY_ARRAY_DESCRIPTOR('f', float);
+static GraalPyArray_Descriptor array_descriptor_d = GRAALPY_ARRAY_DESCRIPTOR('d', double);
+
+#undef GRAALPY_ARRAY_DESCRIPTOR
+
+GraalPyArray_Descriptor *
+GraalPyArray_GetDescriptor(PyObject *array)
+{
+ switch (GraalPyPrivate_Array_TypeCode(array)) {
+ case 'b': return &array_descriptor_b;
+ case 'B': return &array_descriptor_B;
+ case 'u': return &array_descriptor_u;
+ case 'w': return &array_descriptor_w;
+ case 'h': return &array_descriptor_h;
+ case 'H': return &array_descriptor_H;
+ case 'i': return &array_descriptor_i;
+ case 'I': return &array_descriptor_I;
+ case 'l': return &array_descriptor_l;
+ case 'L': return &array_descriptor_L;
+ case 'q': return &array_descriptor_q;
+ case 'Q': return &array_descriptor_Q;
+ case 'f': return &array_descriptor_f;
+ case 'd': return &array_descriptor_d;
+ default:
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+}
+
+PyObject *
+GraalPyArray_New(PyObject *type, Py_ssize_t size, GraalPyArray_Descriptor *descriptor)
+{
+ if (type == NULL || descriptor == NULL || size < 0) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ return GraalPyPrivate_Array_New(type, size, (unsigned char)descriptor->typecode);
+}
diff --git a/graalpython/com.oracle.graal.python.cext/src/memoryobject.c b/graalpython/com.oracle.graal.python.cext/src/memoryobject.c
index c3b34413b9..a51e7346b7 100644
--- a/graalpython/com.oracle.graal.python.cext/src/memoryobject.c
+++ b/graalpython/com.oracle.graal.python.cext/src/memoryobject.c
@@ -3520,3 +3520,16 @@ GraalPyPrivate_ReleaseBuffer(Py_buffer* buffer)
}
free(buffer);
}
+
+// GraalPy additions
+Py_buffer *
+GraalPyMemoryView_GET_BUFFER(PyObject *op)
+{
+ return &_PyMemoryView_CAST(op)->view;
+}
+
+PyObject *
+GraalPyMemoryView_GET_BASE(PyObject *op)
+{
+ return _PyMemoryView_CAST(op)->view.obj;
+}
diff --git a/graalpython/com.oracle.graal.python.cext/src/pylifecycle.c b/graalpython/com.oracle.graal.python.cext/src/pylifecycle.c
index 0d6e6a774a..8375849147 100644
--- a/graalpython/com.oracle.graal.python.cext/src/pylifecycle.c
+++ b/graalpython/com.oracle.graal.python.cext/src/pylifecycle.c
@@ -74,6 +74,13 @@ Py_IsFinalizing(void)
return graalpy_finalizing;
}
+// GraalPy change: compatibility alias for pybind11
+int
+_Py_IsFinalizing(void)
+{
+ return Py_IsFinalizing();
+}
+
static void
graalpy_fork_not_supported(void)
{
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_array.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_array.py
index 4d10e16cdc..68af1a88d4 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_array.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_array.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# The Universal Permissive License (UPL), Version 1.0
@@ -56,9 +56,24 @@ def reference_getbuffer(args):
return a, bytes(a), len(a) * a.itemsize, a.itemsize, 0, 1, a.typecode, len(a), a.itemsize
+def reference_array_new(args):
+ array_type, size, template = args
+ result = array_type(template.typecode, [0] * size)
+ return type(result) is array_type, result
+
+
+def reference_array_descriptor(args):
+ array_obj, other = args
+ return array_obj.typecode, True, array_obj.typecode == other.typecode
+
+
TEST_ARRAY = array('i', [1, 2, 3])
+class ArraySubclass(array):
+ pass
+
+
class TestPyArray(CPyExtTestCase):
if sys.implementation.name == 'graalpy':
@@ -103,6 +118,106 @@ class TestPyArray(CPyExtTestCase):
cmpfunc=unhandled_error_compare,
)
+ test_GraalPyArray_New = CPyExtFunction(
+ reference_array_new,
+ lambda: (
+ (array, 0, array('b')),
+ (array, 3, array('i')),
+ (ArraySubclass, 2, array('d')),
+ ),
+ code="""
+ PyObject* wrap_GraalPyArray_New(PyObject* type, Py_ssize_t size, PyObject* template) {
+ GraalPyArray_Descriptor* descriptor = GraalPyArray_GetDescriptor(template);
+ if (descriptor == NULL)
+ return NULL;
+ PyObject* result = GraalPyArray_New(type, size, descriptor);
+ if (result == NULL)
+ return NULL;
+ PyObject* is_requested_type = PyBool_FromLong(Py_TYPE(result) == (PyTypeObject*)type);
+ if (is_requested_type == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ return Py_BuildValue("NN", is_requested_type, result);
+ }
+ """,
+ callfunction="wrap_GraalPyArray_New",
+ resultspec="O",
+ argspec="OnO",
+ arguments=["PyObject* type", "Py_ssize_t size", "PyObject* template"],
+ cmpfunc=unhandled_error_compare,
+ )
+
+ test_GraalPyArray_Descriptor = CPyExtFunction(
+ reference_array_descriptor,
+ lambda: (
+ (array('b'), array('b')),
+ (array('B'), array('B')),
+ (array('u'), array('u')),
+ (array('w'), array('w')),
+ (array('h'), array('h')),
+ (array('H'), array('H')),
+ (array('i'), array('I')),
+ (array('I'), array('I')),
+ (array('l'), array('l')),
+ (array('L'), array('L')),
+ (array('q'), array('q')),
+ (array('Q'), array('Q')),
+ (array('f'), array('f')),
+ (array('d'), array('d')),
+ ),
+ code="""
+ PyObject* wrap_GraalPyArray_Descriptor(PyObject* array, PyObject* other) {
+ GraalPyArray_Descriptor* descriptor = GraalPyArray_GetDescriptor(array);
+ GraalPyArray_Descriptor* other_descriptor = GraalPyArray_GetDescriptor(other);
+ PyObject* typecode;
+ PyObject* itemsize;
+ long itemsize_value;
+ if (descriptor == NULL || other_descriptor == NULL)
+ return NULL;
+ typecode = PyUnicode_FromOrdinal((unsigned char)descriptor->typecode);
+ if (typecode == NULL)
+ return NULL;
+ itemsize = PyObject_GetAttrString(array, "itemsize");
+ if (itemsize == NULL) {
+ Py_DECREF(typecode);
+ return NULL;
+ }
+ itemsize_value = PyLong_AsLong(itemsize);
+ Py_DECREF(itemsize);
+ if (itemsize_value == -1 && PyErr_Occurred()) {
+ Py_DECREF(typecode);
+ return NULL;
+ }
+ return Py_BuildValue("Nii", typecode, descriptor->itemsize == itemsize_value,
+ descriptor == other_descriptor);
+ }
+ """,
+ callfunction="wrap_GraalPyArray_Descriptor",
+ resultspec="O",
+ argspec="OO",
+ arguments=["PyObject* array", "PyObject* other"],
+ cmpfunc=unhandled_error_compare,
+ )
+
+ test_array_Py_SIZE = CPyExtFunction(
+ lambda args: len(args[0]),
+ lambda: (
+ (array('b'),),
+ (array('i', [1, 2, 3]),),
+ (ArraySubclass('d', [1, 2]),),
+ ),
+ code="""
+ Py_ssize_t wrap_array_Py_SIZE(PyObject* array) {
+ return Py_SIZE(array);
+ }
+ """,
+ callfunction="wrap_array_Py_SIZE",
+ resultspec="n",
+ argspec="O",
+ arguments=["PyObject* array"],
+ )
+
test_array_getbuffer = CPyExtFunction(
reference_getbuffer,
lambda: (
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py
index 33ca0cf196..46876e6ff3 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_codeobject.py
@@ -60,6 +60,19 @@ def example_function():
return 1
+def make_closure_function():
+ first = 1
+ second = 2
+
+ def closure_function():
+ return first + second
+
+ return closure_function
+
+
+closure_function = make_closure_function()
+
+
def reference_PyCode_Addr2Line(args):
code, lasti = args
if lasti >= 0:
@@ -80,6 +93,23 @@ class TestCodeobject(CPyExtTestCase):
testmod = type(sys)("foo")
+ test_PyCode_GetNumFree = CPyExtFunction(
+ lambda args: len(args[0].co_freevars),
+ lambda: (
+ (example_function.__code__,),
+ (closure_function.__code__,),
+ ),
+ code="""
+ static Py_ssize_t wrap_PyCode_GetNumFree(PyObject *code) {
+ return PyCode_GetNumFree((PyCodeObject *)code);
+ }
+ """,
+ resultspec="n",
+ argspec="O",
+ arguments=["PyObject* code"],
+ callfunction="wrap_PyCode_GetNumFree",
+ )
+
test_PyCode_NewEmpty = CPyExtFunction(
lambda args: args,
lambda: (
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_context.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_context.py
index 4dc0896d45..c60c396b1f 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_context.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_context.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024, 2024, 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
@@ -71,13 +71,26 @@
static PyObject* context_copy_current(PyObject* unused, PyObject* args) {
return PyContext_CopyCurrent();
}
+ static PyObject* context_is_exact_type(PyObject* unused, PyObject* args) {
+ PyObject *obj;
+ int kind;
+ if (!PyArg_ParseTuple(args, "Oi", &obj, &kind))
+ return NULL;
+ PyTypeObject *expected_types[] = {
+ &PyContext_Type,
+ &PyContextVar_Type,
+ &PyContextToken_Type,
+ };
+ return PyBool_FromLong(Py_IS_TYPE(obj, expected_types[kind]));
+ }
''',
tp_methods='''
{"enter", (PyCFunction)context_enter, METH_VARARGS | METH_STATIC, ""},
{"exit", (PyCFunction)context_exit, METH_VARARGS | METH_STATIC, ""},
{"copy", (PyCFunction)context_copy, METH_VARARGS | METH_STATIC, ""},
{"new", (PyCFunction)context_new, METH_VARARGS | METH_STATIC, ""},
- {"copy_current", (PyCFunction)context_copy_current, METH_VARARGS | METH_STATIC, ""}
+ {"copy_current", (PyCFunction)context_copy_current, METH_VARARGS | METH_STATIC, ""},
+ {"is_exact_type", (PyCFunction)context_is_exact_type, METH_VARARGS | METH_STATIC, ""}
'''
)
@@ -91,6 +104,10 @@ def test_cext_context_management():
assert v.get() == 'new value'
current_copy = ContextHelper.copy_current()
+ assert ContextHelper.is_exact_type(current_copy, 0)
+ assert ContextHelper.is_exact_type(v, 1)
+ assert ContextHelper.is_exact_type(token, 2)
+
assert v.get() == 'new value'
assert current_copy.run(v.get) == 'new value'
@@ -120,4 +137,4 @@ def test_cext_context_management():
assert copy_of_copy.run(v.get) == 'newer value 2'
new_ctx = ContextHelper.new()
- assert new_ctx.run(v.get) == 'default value'
\ No newline at end of file
+ assert new_ctx.run(v.get) == 'default value'
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py
index 34b59cca6e..38228de256 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_dict.py
@@ -176,6 +176,11 @@ class SubDict(dict):
pass
+class DictWithOverriddenLen(dict):
+ def __len__(self):
+ return 42
+
+
ExampleDict = {}
@@ -593,6 +598,20 @@ class TestPyDict(CPyExtTestCase):
arguments=["PyObject* dict"],
)
+ test_PyDict_GET_SIZE = CPyExtFunction(
+ lambda args: dict.__len__(args[0]),
+ lambda: (
+ ({},),
+ ({'a': "hello"},),
+ ({'a': "hello", 'b': "world"},),
+ (SubDict({'a': "hello"}),),
+ (DictWithOverriddenLen({'a': "hello", 'b': "world"}),),
+ ),
+ resultspec="n",
+ argspec='O',
+ arguments=["PyObject* dict"],
+ )
+
# PyDict_Copy
test_PyDict_Copy = CPyExtFunction(
_reference_copy,
@@ -659,6 +678,48 @@ class TestPyDict(CPyExtTestCase):
arguments=["PyObject* o"],
)
+ test_PyDictView_Type = CPyExtFunction(
+ lambda args: True,
+ lambda: (
+ ({}.keys(), 0),
+ ({}.items(), 1),
+ ({}.values(), 2),
+ ),
+ code='''int wrap_PyDictView_Type(PyObject* view, int kind) {
+ PyTypeObject* expected_types[] = {
+ &PyDictKeys_Type,
+ &PyDictItems_Type,
+ &PyDictValues_Type,
+ };
+ return Py_IS_TYPE(view, expected_types[kind]);
+ }''',
+ resultspec="i",
+ argspec="Oi",
+ arguments=["PyObject* view", "int kind"],
+ callfunction="wrap_PyDictView_Type",
+ )
+
+ test_PyDictIter_Type = CPyExtFunction(
+ lambda args: True,
+ lambda: (
+ (iter({}), 0),
+ (iter({}.values()), 1),
+ (iter({}.items()), 2),
+ ),
+ code='''int wrap_PyDictIter_Type(PyObject* iterator, int kind) {
+ PyTypeObject* expected_types[] = {
+ &PyDictIterKey_Type,
+ &PyDictIterValue_Type,
+ &PyDictIterItem_Type,
+ };
+ return Py_IS_TYPE(iterator, expected_types[kind]);
+ }''',
+ resultspec="i",
+ argspec="Oi",
+ arguments=["PyObject* iterator", "int kind"],
+ callfunction="wrap_PyDictIter_Type",
+ )
+
test_PyDict_Update = CPyExtFunction(
lambda args: 1 if args[0].update(args[1]) else 0,
lambda: (
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 ba63aa5295..8a7f4a7071 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
@@ -39,6 +39,7 @@
import os
import sys
+import types
import unittest
from . import (
@@ -82,6 +83,43 @@ def identCallResult(arg):
return ident(arg)
+def _make_function_with_fields():
+ closed_over = 42
+
+ def function(positional="default", *, keyword="kwdefault") -> int:
+ return closed_over
+
+ return function
+
+
+function_with_fields = _make_function_with_fields()
+
+
+def function_without_optional_fields():
+ pass
+
+
+def _reference_cell_get(args):
+ cell = args[0]
+ if not isinstance(cell, types.CellType):
+ raise SystemError
+ return cell.cell_contents
+
+
+def _reference_cell_set(args):
+ cell, value, clear = args
+ if not isinstance(cell, types.CellType):
+ raise SystemError
+ if clear:
+ del cell.cell_contents
+ else:
+ cell.cell_contents = value
+ try:
+ return False, cell.cell_contents
+ except ValueError:
+ return True, None
+
+
class TypeWithAttr:
attr = "str"
@@ -122,6 +160,97 @@ def __delitem__(self, key):
class TestPyObject(CPyExtTestCase):
+ test_PyCell_Get = CPyExtFunction(
+ _reference_cell_get,
+ lambda: (
+ (types.CellType(42),),
+ (types.CellType(["value"]),),
+ (42,),
+ ),
+ code="""
+ static PyObject* wrap_PyCell_Get(PyObject* cell) {
+ return PyCell_Get(cell);
+ }
+ """,
+ argspec="O",
+ arguments=["PyObject* cell"],
+ resultspec="N",
+ callfunction="wrap_PyCell_Get",
+ cmpfunc=unhandled_error_compare,
+ )
+
+ test_PyCell_GET_macro = CPyExtFunction(
+ lambda args: (args[0].cell_contents, True),
+ lambda: (
+ (types.CellType(42),),
+ (types.CellType(["value"]),),
+ ),
+ code="""
+ static PyObject* wrap_PyCell_GET(PyObject* cell) {
+ PyObject *contents = PyCell_GET(cell);
+ PyObject *contents_attr = PyObject_GetAttrString(cell, "cell_contents");
+ PyObject *result;
+
+ if (contents_attr == NULL) {
+ return NULL;
+ }
+ result = PyTuple_Pack(2, contents, contents == contents_attr ? Py_True : Py_False);
+ Py_DECREF(contents_attr);
+ return result;
+ }
+ """,
+ argspec="O",
+ arguments=["PyObject* cell"],
+ callfunction="wrap_PyCell_GET",
+ )
+
+ test_PyCell_Set = CPyExtFunction(
+ _reference_cell_set,
+ lambda: (
+ (types.CellType(), 42, False),
+ (types.CellType("old"), ["new"], False),
+ (types.CellType("old"), None, True),
+ (42, "new", False),
+ ),
+ code="""
+ static PyObject* wrap_PyCell_Set(PyObject* cell, PyObject* value, int clear) {
+ PyObject *contents;
+ if (PyCell_Set(cell, clear ? NULL : value) < 0) {
+ return NULL;
+ }
+ contents = PyCell_GET(cell);
+ return Py_BuildValue("(iO)", contents == NULL, contents == NULL ? Py_None : contents);
+ }
+ """,
+ argspec="OOp",
+ arguments=["PyObject* cell", "PyObject* value", "int clear"],
+ callfunction="wrap_PyCell_Set",
+ cmpfunc=unhandled_error_compare,
+ )
+
+ test_PyCell_SET_macro = CPyExtFunction(
+ _reference_cell_set,
+ lambda: (
+ (types.CellType(), 42, False),
+ (types.CellType("old"), ["new"], False),
+ (types.CellType("old"), None, True),
+ ),
+ code="""
+ static PyObject* wrap_PyCell_SET(PyObject* cell, PyObject* value, int clear) {
+ PyObject *contents;
+ if (!clear) {
+ Py_INCREF(value);
+ }
+ PyCell_SET(cell, clear ? NULL : value);
+ contents = PyCell_GET(cell);
+ return Py_BuildValue("(iO)", contents == NULL, contents == NULL ? Py_None : contents);
+ }
+ """,
+ argspec="OOp",
+ arguments=["PyObject* cell", "PyObject* value", "int clear"],
+ callfunction="wrap_PyCell_SET",
+ )
+
test_Py_TYPE = CPyExtFunction(
type,
@@ -652,6 +781,57 @@ def _ref_hash_not_implemented(args):
callfunction="wrapGraalPyCFunction_GetMethodDef",
cmpfunc=unhandled_error_compare
)
+
+ test_PyFunction_GET_FIELDS = CPyExtFunction(
+ lambda args: (
+ args[0].__code__,
+ args[0].__globals__,
+ args[0].__module__,
+ args[0].__defaults__,
+ args[0].__kwdefaults__,
+ args[0].__closure__,
+ args[0].__annotations__ or None,
+ True,
+ ),
+ lambda: (
+ (function_with_fields,),
+ (function_without_optional_fields,),
+ ),
+ code="""
+ static PyObject* wrap_PyFunction_GET_FIELDS(PyObject* function) {
+ PyObject *module = PyFunction_GET_MODULE(function);
+ PyObject *defaults = PyFunction_GET_DEFAULTS(function);
+ PyObject *kwdefaults = PyFunction_GET_KW_DEFAULTS(function);
+ PyObject *closure = PyFunction_GET_CLOSURE(function);
+ PyObject *annotations = PyFunction_GET_ANNOTATIONS(function);
+ PyObject *module_attr = PyObject_GetAttrString(function, "__module__");
+ PyObject *result;
+ int stable_module;
+
+ if (module_attr == NULL) {
+ return NULL;
+ }
+ stable_module = module == module_attr;
+ Py_DECREF(module_attr);
+
+ result = PyTuple_Pack(
+ 8,
+ PyFunction_GET_CODE(function),
+ PyFunction_GET_GLOBALS(function),
+ module,
+ defaults != NULL ? defaults : Py_None,
+ kwdefaults != NULL ? kwdefaults : Py_None,
+ closure != NULL ? closure : Py_None,
+ annotations != NULL ? annotations : Py_None,
+ stable_module ? Py_True : Py_False
+ );
+ return result;
+ }
+ """,
+ argspec="O",
+ arguments=["PyObject* function"],
+ callfunction="wrap_PyFunction_GET_FIELDS",
+ )
# create function from PyMethodDef
# test PyMethodDef is same
# test calling m_meth
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_memoryview.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_memoryview.py
index c4d3ac3e99..200a1b92ee 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_memoryview.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_memoryview.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2019, 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
@@ -320,6 +320,29 @@ class TestPyMemoryView(CPyExtTestCase):
cmpfunc=unhandled_error_compare_with_message,
)
+ test_memoryview_accessors = CPyExtFunction(
+ lambda args: (True, bytes(args[0])),
+ lambda: ((bytearray(b'12345678'),),),
+ code='''
+ static PyObject* test_accessors(PyObject* obj) {
+ PyObject *mv = PyMemoryView_FromObject(obj);
+ if (!mv)
+ return NULL;
+ Py_buffer *view = PyMemoryView_GET_BUFFER(mv);
+ PyObject *result = Py_BuildValue(
+ "NN",
+ PyBool_FromLong(PyMemoryView_GET_BASE(mv) == obj),
+ PyBytes_FromStringAndSize(view->buf, view->len));
+ Py_DECREF(mv);
+ return result;
+ }
+ ''',
+ resultspec='O',
+ argspec='O',
+ arguments=["PyObject* obj"],
+ callfunction="test_accessors",
+ )
+
ignored_test_memoryview_slice = CPyExtFunction(
lambda args: bytes((5, 6, 255, 128, 99))[args[0]][args[1]][args[2]],
lambda: list(itertools.product(slices, slices, range(-2, 5))),
@@ -378,7 +401,7 @@ class TestPyMemoryView(CPyExtTestCase):
0,
"l",
};
-
+
static PyObject* test_read(PyObject *key, PyObject* expected) {
PyObject *mv = PyMemoryView_FromBuffer(&buffer);
if (!mv)
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_misc.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_misc.py
index 7d0510cc3b..908e846e10 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_misc.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_misc.py
@@ -91,8 +91,39 @@ def _reference_builtins(args):
return type(__global_builtins_dict)
+async def _async_generator():
+ yield None
+
+
class TestMisc(CPyExtTestCase):
+ test_builtin_type_objects = CPyExtFunction(
+ lambda args: True,
+ lambda: (
+ (_async_generator().__anext__(), 0),
+ (iter(lambda: None, None), 1),
+ (classmethod(lambda: None), 2),
+ (dict.__dict__["fromkeys"], 3),
+ (staticmethod(lambda: None), 4),
+ ),
+ callfunction="check_builtin_type_object",
+ code='''
+ static int check_builtin_type_object(PyObject* obj, int kind) {
+ PyTypeObject* expected_types[] = {
+ &_PyAsyncGenASend_Type,
+ &PyCallIter_Type,
+ &PyClassMethod_Type,
+ &PyClassMethodDescr_Type,
+ &PyStaticMethod_Type,
+ };
+ return Py_IS_TYPE(obj, expected_types[kind]);
+ }
+ ''',
+ resultspec="i",
+ argspec="Oi",
+ arguments=["PyObject* obj", "int kind"],
+ )
+
test_PyEllipsis_isSingleton = CPyExtFunction(
lambda args: 1,
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 bf9a6d9d65..8f05308339 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
@@ -38,6 +38,7 @@
# SOFTWARE.
import sys
+import typing
import unittest
from unittest import skipIf
@@ -1596,6 +1597,21 @@ class DummyBytes(bytes):
class TestObjectFunctions(CPyExtTestCase):
+ test_abstract_object_constants_native_roundtrip = CPyExtFunction(
+ lambda args: args[0],
+ lambda: (
+ (None,),
+ (Ellipsis,),
+ (NotImplemented,),
+ (typing.NoDefault,),
+ ),
+ arguments=["PyObject* obj"],
+ resultspec="N",
+ argspec="O",
+ callfunction="Py_NewRef",
+ cmpfunc=lambda actual, expected: actual is expected,
+ )
+
test_PyCallable_Check = CPyExtFunction(
lambda args: callable(args[0]),
lambda: (
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py b/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py
index 812ad76bd5..fc0a893df1 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py
@@ -434,6 +434,20 @@ def inner():
assert update_freevar() == (2, 2)
+def test_f_locals_proxy_cell_parameter_after_return():
+ def get_frame(cell_parameter):
+ def read_cell_parameter():
+ return cell_parameter
+
+ return sys._getframe(), read_cell_parameter
+
+ frame, read_cell_parameter = get_frame(1)
+ locals_proxy = frame.f_locals
+ assert locals_proxy['cell_parameter'] == 1
+ locals_proxy['cell_parameter'] = 2
+ assert read_cell_parameter() == 2
+
+
OTHER_RUNNING_INNER = 'running_inner'
OTHER_RUNNING_OUTER = 'running_outer'
OTHER_TERMINATED = 'terminated'
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_id.py b/graalpython/com.oracle.graal.python.test/src/tests/test_id.py
index 210a8fe462..3d1d695ceb 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/test_id.py
+++ b/graalpython/com.oracle.graal.python.test/src/tests/test_id.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2018, 2024, 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
@@ -38,6 +38,7 @@
# SOFTWARE.
import sys
+import typing
def test_small_int_id_is_constant():
@@ -53,6 +54,13 @@ def test_object_id_is_constant():
assert id(x) == xid
+def test_abstract_object_constants_have_id():
+ for constant in (None, Ellipsis, NotImplemented, typing.NoDefault):
+ constant_id = id(constant)
+ assert isinstance(constant_id, int)
+ assert id(constant) == constant_id
+
+
def test_double_id_is_constant():
assert id(12.2) == id(12.2)
x = 128.12
@@ -95,4 +103,3 @@ def test_string_interned():
# y = x * 2
# z = x * 2
# assert id(y) != id(z)
-
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 a3fab2f075..9a3a9ba1c7 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
@@ -52,7 +52,8 @@ def test_platform_sysconfigdata():
import sysconfig
mod = importlib.import_module(sysconfig._get_sysconfigdata_name())
# These flags are parsed directly from the file by maturin
- for key in ("ABIFLAGS", "EXT_SUFFIX", "SOABI", "VERSION"):
+ for key in ("ABIFLAGS", "EXT_SUFFIX", "INSTSONAME", "SOABI", "VERSION"):
assert key in mod.build_time_vars
assert mod.build_time_vars["ABIFLAGS"] == sys.abiflags
+ assert mod.build_time_vars["INSTSONAME"] == mod.build_time_vars["LDLIBRARY"]
assert sys.abiflags in sysconfig.get_config_var("INCLUDEPY")
diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_marshal.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_marshal.txt
index f68eaa6e60..b1396a9f3a 100644
--- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_marshal.txt
+++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_marshal.txt
@@ -18,6 +18,7 @@ test.test_marshal.BugsTestCase.test_version_argument @ darwin-arm64,linux-aarch6
!test.test_marshal.CodeTestCase.test_code
test.test_marshal.CodeTestCase.test_different_filenames @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github
test.test_marshal.CodeTestCase.test_many_codeobjects @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github
+test.test_marshal.CodeTestCase.test_no_allow_code @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github
test.test_marshal.CompatibilityTestCase.test0To3 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github
test.test_marshal.CompatibilityTestCase.test1To3 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github
test.test_marshal.CompatibilityTestCase.test2To3 @ 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/src/com/oracle/graal/python/PythonLanguage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java
index 8de2783999..8dd6298e85 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
@@ -77,6 +77,7 @@
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
import com.oracle.graal.python.builtins.objects.type.TpSlots;
import com.oracle.graal.python.builtins.objects.type.slots.TpSlot;
+import com.oracle.graal.python.builtins.objects.typing.PNoDefault;
import com.oracle.graal.python.compiler.ParserCallbacksImpl;
import com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompiler;
import com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompiler.BytecodeDSLCompilerResult;
@@ -365,7 +366,7 @@ public boolean isSingleContext() {
@CompilationFinal(dimensions = 1) private final Shape[] builtinTypeInstanceShapes = new Shape[PythonBuiltinClassType.VALUES.length];
@CompilationFinal(dimensions = 1) public static final PythonAbstractObject[] CONTEXT_INSENSITIVE_SINGLETONS = new PythonAbstractObject[]{PNone.NONE, PEllipsis.INSTANCE,
- PNotImplemented.NOT_IMPLEMENTED};
+ PNotImplemented.NOT_IMPLEMENTED, PNoDefault.NO_DEFAULT};
@CompilationFinal(dimensions = 1) private volatile Object[] engineOptionsStorage;
@CompilationFinal private volatile OptionValues engineOptions;
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java
index 5e3a8c62f3..70af888874 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MarshalModuleBuiltins.java
@@ -119,10 +119,9 @@
import com.oracle.graal.python.nodes.bytecode_dsl.PBytecodeDSLRootNodeGen;
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
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.PythonQuaternaryClinicBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryClinicBuiltinNode;
-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.ExecutionContext.BoundaryCallContext;
import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData;
@@ -174,17 +173,18 @@ public void initialize(Python3Core core) {
addBuiltinConstant(T_VERSION, CURRENT_VERSION);
}
- @Builtin(name = "dump", minNumOfPositionalArgs = 2, parameterNames = {"value", "file", "version"})
+ @Builtin(name = "dump", minNumOfPositionalArgs = 2, numOfPositionalOnlyArgs = 3, parameterNames = {"value", "file", "version"}, keywordOnlyNames = "allow_code")
@ArgumentClinic(name = "version", defaultValue = "CURRENT_VERSION", conversion = ClinicConversion.Int)
+ @ArgumentClinic(name = "allow_code", defaultValue = "true", conversion = ClinicConversion.Boolean)
@GenerateNodeFactory
- abstract static class DumpNode extends PythonTernaryClinicBuiltinNode {
+ abstract static class DumpNode extends PythonQuaternaryClinicBuiltinNode {
@Override
protected ArgumentClinicProvider getArgumentClinic() {
return DumpNodeClinicProviderGen.INSTANCE;
}
@Specialization
- static Object doit(VirtualFrame frame, Object value, Object file, int version,
+ static Object doit(VirtualFrame frame, Object value, Object file, int version, boolean allowCode,
@Bind Node inliningTarget,
@Bind PythonContext context,
@Cached("createFor($node)") BoundaryCallData boundaryCallData,
@@ -195,7 +195,7 @@ static Object doit(VirtualFrame frame, Object value, Object file, int version,
Object savedState = BoundaryCallContext.enter(frame, threadState, boundaryCallData);
byte[] data;
try {
- data = Marshal.dump(language, value, version);
+ data = Marshal.dump(language, value, version, allowCode);
} catch (IOException e) {
throw CompilerDirectives.shouldNotReachHere(e);
} catch (Marshal.MarshalError me) {
@@ -207,17 +207,18 @@ static Object doit(VirtualFrame frame, Object value, Object file, int version,
}
}
- @Builtin(name = "dumps", minNumOfPositionalArgs = 1, parameterNames = {"value", "version"})
+ @Builtin(name = "dumps", minNumOfPositionalArgs = 1, numOfPositionalOnlyArgs = 2, parameterNames = {"value", "version"}, keywordOnlyNames = "allow_code")
@ArgumentClinic(name = "version", defaultValue = "CURRENT_VERSION", conversion = ClinicConversion.Int)
+ @ArgumentClinic(name = "allow_code", defaultValue = "true", conversion = ClinicConversion.Boolean)
@GenerateNodeFactory
- abstract static class DumpsNode extends PythonBinaryClinicBuiltinNode {
+ abstract static class DumpsNode extends PythonTernaryClinicBuiltinNode {
@Override
protected ArgumentClinicProvider getArgumentClinic() {
return DumpsNodeClinicProviderGen.INSTANCE;
}
@Specialization
- static Object doit(VirtualFrame frame, Object value, int version,
+ static Object doit(VirtualFrame frame, Object value, int version, boolean allowCode,
@Bind Node inliningTarget,
@Bind PythonContext context,
@Cached("createFor($node)") BoundaryCallData boundaryCallData,
@@ -226,7 +227,7 @@ static Object doit(VirtualFrame frame, Object value, int version,
PythonContext.PythonThreadState threadState = context.getThreadState(language);
Object savedState = BoundaryCallContext.enter(frame, threadState, boundaryCallData);
try {
- return PFactory.createBytes(language, Marshal.dump(language, value, version));
+ return PFactory.createBytes(language, Marshal.dump(language, value, version, allowCode));
} catch (IOException e) {
throw CompilerDirectives.shouldNotReachHere(e);
} catch (Marshal.MarshalError me) {
@@ -237,16 +238,22 @@ static Object doit(VirtualFrame frame, Object value, int version,
}
}
- @Builtin(name = "load", minNumOfPositionalArgs = 1)
+ @Builtin(name = "load", minNumOfPositionalArgs = 1, numOfPositionalOnlyArgs = 1, parameterNames = "file", keywordOnlyNames = "allow_code")
+ @ArgumentClinic(name = "allow_code", defaultValue = "true", conversion = ClinicConversion.Boolean)
@GenerateNodeFactory
- abstract static class LoadNode extends PythonBuiltinNode {
+ abstract static class LoadNode extends PythonBinaryClinicBuiltinNode {
+ @Override
+ protected ArgumentClinicProvider getArgumentClinic() {
+ return MarshalModuleBuiltinsClinicProviders.LoadNodeClinicProviderGen.INSTANCE;
+ }
+
@NeverDefault
protected static LookupAndCallBinaryNode createCallReadNode() {
return LookupAndCallBinaryNode.create(T_READ);
}
@Specialization
- static Object doit(VirtualFrame frame, Object file,
+ static Object doit(VirtualFrame frame, Object file, boolean allowCode,
@Bind Node inliningTarget,
@Bind PythonContext context,
@Cached("createCallReadNode()") LookupAndCallBinaryNode callNode,
@@ -258,7 +265,7 @@ static Object doit(VirtualFrame frame, Object file,
throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.READ_RETURNED_NOT_BYTES, buffer);
}
try {
- return Marshal.loadFile(language, file);
+ return Marshal.loadFile(language, file, allowCode);
} catch (NumberFormatException e) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BAD_MARSHAL_DATA_S, e.getMessage());
} catch (Marshal.MarshalError me) {
@@ -267,13 +274,14 @@ static Object doit(VirtualFrame frame, Object file,
}
}
- @Builtin(name = "loads", minNumOfPositionalArgs = 1, numOfPositionalOnlyArgs = 1, parameterNames = {"bytes"})
+ @Builtin(name = "loads", minNumOfPositionalArgs = 1, numOfPositionalOnlyArgs = 1, parameterNames = {"bytes"}, keywordOnlyNames = "allow_code")
@ArgumentClinic(name = "bytes", conversion = ClinicConversion.ReadableBuffer)
+ @ArgumentClinic(name = "allow_code", defaultValue = "true", conversion = ClinicConversion.Boolean)
@GenerateNodeFactory
- abstract static class LoadsNode extends PythonUnaryClinicBuiltinNode {
+ abstract static class LoadsNode extends PythonBinaryClinicBuiltinNode {
@Specialization
- static Object doit(VirtualFrame frame, Object buffer,
+ static Object doit(VirtualFrame frame, Object buffer, boolean allowCode,
@Bind Node inliningTarget,
@Bind PythonContext context,
@Cached("createFor($node)") InteropCallData callData,
@@ -287,7 +295,7 @@ static Object doit(VirtualFrame frame, Object buffer,
if (!language.isSingleContext()) {
cacheKey = language.cacheKeyForBytecode(bytes, length);
}
- return Marshal.load(language, bytes, length, cacheKey);
+ return Marshal.load(language, bytes, length, cacheKey, allowCode);
} catch (NumberFormatException e) {
throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.BAD_MARSHAL_DATA_S, e.getMessage());
} catch (Marshal.MarshalError me) {
@@ -390,15 +398,20 @@ public final Throwable fillInStackTrace() {
}
@TruffleBoundary
- static byte[] dump(PythonLanguage language, Object value, int version) throws IOException, MarshalError {
- Marshal outMarshal = new Marshal(language, version);
+ static byte[] dump(PythonLanguage language, Object value, int version, boolean allowCode) throws IOException, MarshalError {
+ Marshal outMarshal = new Marshal(language, version, allowCode);
outMarshal.writeObject(value);
return outMarshal.outData.toByteArray();
}
@TruffleBoundary
static Object load(PythonLanguage language, byte[] ary, int length, long cacheKey) throws NumberFormatException, MarshalError {
- Marshal inMarshal = new Marshal(language, ary, length, cacheKey);
+ return load(language, ary, length, cacheKey, true);
+ }
+
+ @TruffleBoundary
+ static Object load(PythonLanguage language, byte[] ary, int length, long cacheKey, boolean allowCode) throws NumberFormatException, MarshalError {
+ Marshal inMarshal = new Marshal(language, ary, length, cacheKey, allowCode);
Object result = inMarshal.readObject();
if (result == null) {
throw new MarshalError(PythonBuiltinClassType.TypeError, ErrorMessages.BAD_MARSHAL_DATA_NULL);
@@ -407,8 +420,8 @@ static Object load(PythonLanguage language, byte[] ary, int length, long cacheKe
}
@TruffleBoundary
- static Object loadFile(PythonLanguage language, Object file) throws NumberFormatException, MarshalError {
- Marshal inMarshal = new Marshal(language, file);
+ static Object loadFile(PythonLanguage language, Object file, boolean allowCode) throws NumberFormatException, MarshalError {
+ Marshal inMarshal = new Marshal(language, file, allowCode);
Object result = inMarshal.readObject();
if (result == null) {
throw new MarshalError(PythonBuiltinClassType.TypeError, ErrorMessages.BAD_MARSHAL_DATA_NULL);
@@ -469,6 +482,7 @@ public int read(byte[] b, int off, int len) {
final DataOutput out;
final DataInput in;
final int version;
+ final boolean allowCode;
int depth = 0;
long cacheKey;
TruffleFile bytecodeFile;
@@ -484,8 +498,13 @@ public int read(byte[] b, int off, int len) {
Source source = null;
Marshal(PythonLanguage language, int version) {
+ this(language, version, true);
+ }
+
+ Marshal(PythonLanguage language, int version, boolean allowCode) {
this.language = language;
this.version = version;
+ this.allowCode = allowCode;
this.outData = new ByteArrayOutputStream();
this.out = new DataOutputStream(outData);
this.refMap = new HashMap<>();
@@ -496,6 +515,7 @@ public int read(byte[] b, int off, int len) {
Marshal(PythonLanguage language, int version, DataOutput out) {
this.language = language;
this.version = version;
+ this.allowCode = true;
this.outData = null;
this.out = out;
this.refMap = new HashMap<>();
@@ -504,24 +524,37 @@ public int read(byte[] b, int off, int len) {
}
Marshal(PythonLanguage language, byte[] in, int length, long cacheKey) {
- this(language, SerializationUtils.createByteBufferDataInput(ByteBuffer.wrap(in, 0, length)), null, 0);
+ this(language, in, length, cacheKey, true);
+ }
+
+ Marshal(PythonLanguage language, byte[] in, int length, long cacheKey, boolean allowCode) {
+ this(language, SerializationUtils.createByteBufferDataInput(ByteBuffer.wrap(in, 0, length)), null, 0, allowCode);
this.cacheKey = cacheKey;
}
Marshal(PythonLanguage language, byte[] in, int length, long cacheKey, TruffleFile bytecodeFile, int baseOffset) {
- this(language, SerializationUtils.createByteBufferDataInput(ByteBuffer.wrap(in, 0, length)), bytecodeFile, baseOffset);
+ this(language, SerializationUtils.createByteBufferDataInput(ByteBuffer.wrap(in, 0, length)), bytecodeFile, baseOffset, true);
this.cacheKey = cacheKey;
}
Marshal(PythonLanguage language, Object in) {
- this(language, new DataInputStream(new FileLikeInputStream(in)), null, 0);
+ this(language, in, true);
+ }
+
+ Marshal(PythonLanguage language, Object in, boolean allowCode) {
+ this(language, new DataInputStream(new FileLikeInputStream(in)), null, 0, allowCode);
}
Marshal(PythonLanguage language, DataInput in, TruffleFile bytecodeFile, int baseOffset) {
+ this(language, in, bytecodeFile, baseOffset, true);
+ }
+
+ Marshal(PythonLanguage language, DataInput in, TruffleFile bytecodeFile, int baseOffset, boolean allowCode) {
this.language = language;
this.in = in;
this.refList = new ArrayList<>();
this.version = -1;
+ this.allowCode = allowCode;
this.outData = null;
this.out = null;
this.refMap = null;
@@ -923,6 +956,9 @@ private void writeComplexObject(Object v, int flag) {
writeByte(ARRAY_TYPE_OBJECT);
writeObjectArray((Object[]) v);
} else if (v instanceof PCode c) {
+ if (!allowCode) {
+ throw new MarshalError(ValueError, ErrorMessages.MARSHALLING_CODE_OBJECTS_DISALLOWED);
+ }
// we always store code objects in our format, CPython will not read our
// marshalled data when that contains code objects
writeByte(TYPE_GRAALPYTHON_CODE | flag);
@@ -1151,10 +1187,19 @@ private Object readObject(int type, AddRefAndReturn addRef) throws NumberFormatE
set.setDictStorage(setStore);
return set;
case TYPE_GRAALPYTHON_CODE:
+ if (!allowCode) {
+ throw new MarshalError(ValueError, ErrorMessages.UNMARSHALLING_CODE_OBJECTS_DISALLOWED);
+ }
return addRef.run(readCode());
case TYPE_GRAALPYTHON_CODE_UNIT:
+ if (!allowCode) {
+ throw new MarshalError(ValueError, ErrorMessages.UNMARSHALLING_CODE_OBJECTS_DISALLOWED);
+ }
return addRef.run(readRemovedCodeUnitPayload());
case TYPE_GRAALPYTHON_DSL_CODE_UNIT:
+ if (!allowCode) {
+ throw new MarshalError(ValueError, ErrorMessages.UNMARSHALLING_CODE_OBJECTS_DISALLOWED);
+ }
return addRef.run(readBytecodeDSLCodeUnit());
case TYPE_DSL_SOURCE:
return addRef.run(readSource());
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextArrayBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextArrayBuiltins.java
index 47fc8ebd6a..bab0a60c19 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextArrayBuiltins.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextArrayBuiltins.java
@@ -40,12 +40,15 @@
*/
package com.oracle.graal.python.builtins.modules.cext;
+import static com.oracle.graal.python.builtins.PythonBuiltinClassType.MemoryError;
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.CHAR_PTR;
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.PY_BUFFER_PTR;
+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.PyObjectRawPointer;
+import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Void;
import static com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.writeIntField;
@@ -55,6 +58,7 @@
import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.calloc;
import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.free;
import static com.oracle.graal.python.runtime.nativeaccess.NativeMemory.malloc;
+import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
import com.oracle.graal.python.builtins.objects.array.ArrayNodes;
@@ -65,12 +69,36 @@
import com.oracle.graal.python.builtins.objects.cext.structs.CFields;
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess.WriteTruffleStringNode;
+import com.oracle.graal.python.builtins.objects.type.TypeNodes;
+import com.oracle.graal.python.nodes.PRaiseNode;
import com.oracle.graal.python.runtime.nativeaccess.NativeMemory;
+import com.oracle.graal.python.runtime.object.PFactory;
+import com.oracle.graal.python.util.BufferFormat;
+import com.oracle.graal.python.util.OverflowException;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.strings.TruffleString;
public final class PythonCextArrayBuiltins {
+ @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject, Py_ssize_t, Int}, call = Ignored)
+ static long GraalPyPrivate_Array_New(long clsPtr, long size, int typeCode) {
+ Object cls = NativeToPythonInternalNode.executeUncached(clsPtr, false);
+ TruffleString typeCodeString = TruffleString.fromCodePointUncached(typeCode, TS_ENCODING);
+ BufferFormat format = BufferFormat.forArray(typeCodeString, TruffleString.CodePointLengthNode.getUncached(),
+ TruffleString.CodePointAtIndexUTF32Node.getUncached());
+ try {
+ PArray array = PFactory.createArray(cls, TypeNodes.GetInstanceShape.executeUncached(cls), typeCodeString, format, Math.toIntExact(size));
+ return PythonToNativeInternalNode.executeUncached(array, true);
+ } catch (ArithmeticException | OverflowException e) {
+ throw PRaiseNode.raiseStatic(null, MemoryError);
+ }
+ }
+
+ @CApiBuiltin(ret = Int, args = {PyObjectRawPointer}, call = Ignored)
+ static int GraalPyPrivate_Array_TypeCode(long arrayPtr) {
+ return expectArray(arrayPtr, "GraalPyArray_GetDescriptor").getFormatString().codePointAtIndexUncached(0, TS_ENCODING);
+ }
+
/**
* Graalpy-specific function implemented for Cython
*/
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCodeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCodeBuiltins.java
index 5d6391ef4e..b42bd711a7 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCodeBuiltins.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextCodeBuiltins.java
@@ -45,6 +45,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.PyCodeObjectRawPointer;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectRawPointer;
+import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
import static com.oracle.graal.python.util.PythonUtils.EMPTY_BYTE_ARRAY;
import static com.oracle.graal.python.util.PythonUtils.EMPTY_OBJECT_ARRAY;
import static com.oracle.graal.python.util.PythonUtils.EMPTY_TRUFFLESTRING_ARRAY;
@@ -61,6 +62,18 @@
public final class PythonCextCodeBuiltins {
+ @CApiBuiltin(ret = Py_ssize_t, args = {PyCodeObjectRawPointer}, call = Direct)
+ static long GraalPyCode_GetNumFree(long codePtr) {
+ PCode code = (PCode) NativeToPythonInternalNode.executeUncached(codePtr, false);
+ return code.getFreeVars().length;
+ }
+
+ @CApiBuiltin(ret = Int, args = {PyCodeObjectRawPointer}, call = Direct)
+ static int GraalPyCode_GetFirstFree(long codePtr) {
+ PCode code = (PCode) NativeToPythonInternalNode.executeUncached(codePtr, false);
+ return code.getVarnames().length + code.getCellVars().length;
+ }
+
@CApiBuiltin(ret = PyCodeObjectRawPointer, args = {Int, Int, Int, Int, Int, Int, PyObjectRawPointer, PyObjectRawPointer, PyObjectRawPointer, PyObjectRawPointer, PyObjectRawPointer,
PyObjectRawPointer, PyObjectRawPointer, PyObjectRawPointer, PyObjectRawPointer, Int, PyObjectRawPointer, PyObjectRawPointer}, call = Direct)
static long PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, long codePtr, long constsPtr,
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 f2733756d9..6f73ee6303 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
@@ -56,6 +56,7 @@
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;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer;
+import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_hash_t;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Void;
import static com.oracle.graal.python.nodes.ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC;
@@ -157,6 +158,12 @@ public final class PythonCextDictBuiltins {
private static final CApiTiming TIMING_PYDICT_NEW = CApiTiming.create(false, "PyDict_New");
+ @CApiBuiltin(ret = Py_ssize_t, args = {PyObject}, call = Direct)
+ static long GraalPyDict_GET_SIZE(long dictPtr) {
+ PDict dict = (PDict) NativeToPythonInternalNode.executeUncached(dictPtr, false);
+ return HashingStorageLen.executeUncached(dict.getDictStorage());
+ }
+
@CApiBuiltin(ret = PyObjectTransfer, args = {}, call = Direct, acquireGil = false)
static long PyDict_New() {
CApiTiming.enter();
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFuncBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFuncBuiltins.java
index b0a0b38beb..7ffd7a0115 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFuncBuiltins.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextFuncBuiltins.java
@@ -40,21 +40,43 @@
*/
package com.oracle.graal.python.builtins.modules.cext;
+import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.ConstCharPtrAsTruffleString;
+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.PyObject;
+import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed;
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer;
+import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___ANNOTATIONS__;
+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.runtime.nativeaccess.NativeMemory.NULLPTR;
import com.oracle.graal.python.PythonLanguage;
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBinaryBuiltinNode;
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
import com.oracle.graal.python.builtins.objects.PNone;
+import com.oracle.graal.python.builtins.objects.cell.PCell;
+import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.EnsurePythonObjectNode;
+import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ToNativeBorrowedNode;
+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.capi.transitions.ArgDescriptor;
+import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
+import com.oracle.graal.python.builtins.objects.dict.PDict;
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.method.PBuiltinMethod;
import com.oracle.graal.python.builtins.objects.method.PDecoratedMethod;
+import com.oracle.graal.python.builtins.objects.module.PythonModule;
+import com.oracle.graal.python.nodes.ErrorMessages;
+import com.oracle.graal.python.nodes.PRaiseNode;
+import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
+import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
+import com.oracle.graal.python.nodes.object.GetOrCreateDictNode;
+import com.oracle.graal.python.runtime.PythonContext;
import com.oracle.graal.python.runtime.object.PFactory;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -64,6 +86,170 @@
public final class PythonCextFuncBuiltins {
+ private static PCell getCell(long cellPtr) {
+ return (PCell) NativeToPythonInternalNode.executeUncached(cellPtr, false);
+ }
+
+ private static Object getPromotedCellRef(long cellPtr) {
+ PCell cell = getCell(cellPtr);
+ Object ref = cell.getRef();
+ if (ref == null) {
+ return null;
+ }
+ Object promotedRef = EnsurePythonObjectNode.executeUncached(PythonContext.get(null), ref, false);
+ if (promotedRef != ref) {
+ cell.setRef(promotedRef);
+ }
+ return promotedRef;
+ }
+
+ private static void checkCell(long cellPtr) {
+ Object cell = NativeToPythonInternalNode.executeUncached(cellPtr, false);
+ if (!(cell instanceof PCell)) {
+ throw PRaiseNode.raiseStatic(null, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
+ }
+ }
+
+ @CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct)
+ static long PyCell_Get(long cellPtr) {
+ checkCell(cellPtr);
+ Object ref = getPromotedCellRef(cellPtr);
+ return ref == null ? NULLPTR : PythonToNativeInternalNode.executeNewRefUncached(ref);
+ }
+
+ @CApiBuiltin(ret = Int, args = {PyObject, PyObject}, call = Direct)
+ static int PyCell_Set(long cellPtr, long valuePtr) {
+ checkCell(cellPtr);
+ getCell(cellPtr).setRef(valuePtr == NULLPTR ? null : NativeToPythonInternalNode.executeUncached(valuePtr, false));
+ return 0;
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyCell_GET(long cellPtr) {
+ Object ref = getPromotedCellRef(cellPtr);
+ return ref == null ? NULLPTR : ToNativeBorrowedNode.executeUncached(ref);
+ }
+
+ @CApiBuiltin(ret = ArgDescriptor.Void, args = {PyObject, PyObjectTransfer}, call = Direct)
+ static void GraalPyCell_SET(long cellPtr, long valuePtr) {
+ getCell(cellPtr).setRef(valuePtr == NULLPTR ? null : NativeToPythonInternalNode.executeUncached(valuePtr, true));
+ }
+
+ private static void checkFunction(long functionPtr) {
+ Object function = NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ if (!(function instanceof PFunction)) {
+ throw PRaiseNode.raiseStatic(null, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
+ }
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetCode(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_CODE(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetGlobals(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_GLOBALS(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetModule(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_MODULE(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetDefaults(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_DEFAULTS(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetKwDefaults(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_KW_DEFAULTS(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetClosure(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_CLOSURE(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long PyFunction_GetAnnotations(long functionPtr) {
+ checkFunction(functionPtr);
+ return GraalPyFunction_GET_ANNOTATIONS(functionPtr);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_CODE(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ return ToNativeBorrowedNode.executeUncached(function.getCode());
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_GLOBALS(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ Object globals = function.getGlobals();
+ return ToNativeBorrowedNode.executeUncached(globals instanceof PythonModule ? GetOrCreateDictNode.executeUncached(globals) : globals);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_MODULE(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ Object module = ReadAttributeFromObjectNode.getUncached().execute(function, T___MODULE__);
+ if (module == PNone.NO_VALUE) {
+ Object globals = function.getGlobals();
+ if (globals instanceof PythonModule) {
+ module = ReadAttributeFromObjectNode.getUncached().execute(globals, T___NAME__);
+ if (module == PNone.NO_VALUE) {
+ module = PNone.NONE;
+ }
+ } else if (globals instanceof PDict dict) {
+ module = HashingStorageGetItem.executeUncached(dict.getDictStorage(), T___NAME__);
+ if (module == null) {
+ module = PNone.NONE;
+ }
+ } else {
+ module = PNone.NONE;
+ }
+ }
+ Object promotedModule = EnsurePythonObjectNode.executeUncached(PythonContext.get(null), module, false);
+ WriteAttributeToObjectNode.getUncached().execute(function, T___MODULE__, promotedModule);
+ return ToNativeBorrowedNode.executeUncached(promotedModule);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_DEFAULTS(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ Object[] defaults = function.getDefaults();
+ return defaults.length == 0 ? NULLPTR : ToNativeBorrowedNode.executeUncached(PFactory.createTuple(PythonLanguage.get(null), defaults));
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_KW_DEFAULTS(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ Object defaults = function.getKwDefaultsDict(PythonLanguage.get(null));
+ return defaults == PNone.NONE ? NULLPTR : ToNativeBorrowedNode.executeUncached(defaults);
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_CLOSURE(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ PCell[] closure = function.getClosure();
+ return closure == null ? NULLPTR : ToNativeBorrowedNode.executeUncached(PFactory.createTuple(PythonLanguage.get(null), closure));
+ }
+
+ @CApiBuiltin(ret = PyObjectBorrowed, args = {PyObject}, call = Direct)
+ static long GraalPyFunction_GET_ANNOTATIONS(long functionPtr) {
+ PFunction function = (PFunction) NativeToPythonInternalNode.executeUncached(functionPtr, false);
+ Object annotations = ReadAttributeFromObjectNode.getUncached().execute(function, T___ANNOTATIONS__);
+ return annotations != PNone.NO_VALUE ? ToNativeBorrowedNode.executeUncached(annotations) : NULLPTR;
+ }
+
@CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct)
abstract static class PyStaticMethod_New extends CApiUnaryBuiltinNode {
@Specialization
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/CellBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/CellBuiltins.java
index 4661087d8f..d5bb915ae7 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/CellBuiltins.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/CellBuiltins.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
@@ -47,6 +47,7 @@
import java.util.List;
+import com.oracle.graal.python.PythonLanguage;
import com.oracle.graal.python.annotations.Slot;
import com.oracle.graal.python.annotations.Slot.SlotKind;
import com.oracle.graal.python.annotations.Slot.SlotSignature;
@@ -119,9 +120,10 @@ private Assumption getAssumption() {
@Specialization
Object newCell(@SuppressWarnings("unused") Object cls, Object contents,
@Bind Node inliningTarget,
+ @Bind PythonLanguage language,
@Cached InlinedConditionProfile nonEmptyProfile) {
Assumption assumption = getAssumption();
- PCell cell = PFactory.createCell(assumption);
+ PCell cell = PFactory.createCell(language, assumption);
if (nonEmptyProfile.profile(inliningTarget, !isNoValue(contents))) {
cell.setRef(contents, assumption);
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/PCell.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/PCell.java
index ecbf632968..6e386b4542 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/PCell.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cell/PCell.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2021, 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
@@ -40,18 +40,20 @@
*/
package com.oracle.graal.python.builtins.objects.cell;
-import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
+import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
import com.oracle.graal.python.util.PythonUtils;
import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.object.Shape;
-public final class PCell extends PythonAbstractObject {
+public final class PCell extends PythonBuiltinObject {
private final Assumption effectivelyFinal;
private Object ref;
- public PCell(Assumption effectivelyFinalAssumption) {
+ public PCell(Object cls, Shape instanceShape, Assumption effectivelyFinalAssumption) {
+ super(cls, instanceShape);
this.effectivelyFinal = effectivelyFinalAssumption;
}
@@ -65,10 +67,6 @@ public Object getRef() {
return ref;
}
- public void clearRef(Assumption assumption) {
- setRef(null, assumption);
- }
-
public void clearRef() {
setRef(null);
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java
index e9409c0443..7263c8724f 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java
@@ -649,9 +649,7 @@ public final class CApiFunction {
@CApiBuiltin(name = "PyBytes_DecodeEscape", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString, Py_ssize_t,
ConstCharPtrAsTruffleString}, call = NotImplemented)
@CApiBuiltin(name = "PyBytes_Repr", ret = PyObject, args = {PyObject, Int}, call = NotImplemented)
- @CApiBuiltin(name = "PyCell_Get", ret = PyObject, args = {PyObject}, call = NotImplemented)
@CApiBuiltin(name = "PyCell_New", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyCell_Set", ret = Int, args = {PyObject, PyObject}, call = NotImplemented)
@CApiBuiltin(name = "PyCode_Addr2Location", ret = Int, args = {PyCodeObject, Int, INT_LIST, INT_LIST, INT_LIST, INT_LIST}, call = NotImplemented)
@CApiBuiltin(name = "PyCode_GetCellvars", ret = PyObject, args = {PyCodeObject}, call = NotImplemented)
@CApiBuiltin(name = "PyCode_GetCode", ret = PyObject, args = {PyCodeObject}, call = NotImplemented)
@@ -730,13 +728,6 @@ public final class CApiFunction {
@CApiBuiltin(name = "PyFrame_FastToLocalsWithError", ret = Int, args = {PyFrameObject}, call = NotImplemented)
@CApiBuiltin(name = "PyFrame_GetGenerator", ret = PyObject, args = {PyFrameObject}, call = NotImplemented)
@CApiBuiltin(name = "PyFrame_LocalsToFast", ret = Void, args = {PyFrameObject, Int}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetAnnotations", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetClosure", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetCode", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetDefaults", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetGlobals", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetKwDefaults", ret = PyObject, args = {PyObject}, call = NotImplemented)
- @CApiBuiltin(name = "PyFunction_GetModule", ret = PyObject, args = {PyObject}, call = NotImplemented)
@CApiBuiltin(name = "PyFunction_New", ret = PyObject, args = {PyObject, PyObject}, call = NotImplemented)
@CApiBuiltin(name = "PyFunction_NewWithQualName", ret = PyObject, args = {PyObject, PyObject, PyObject}, call = NotImplemented)
@CApiBuiltin(name = "PyFunction_SetAnnotations", ret = Int, args = {PyObject, PyObject}, call = NotImplemented)
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 a216db85c2..0f551cc7f2 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
@@ -105,7 +105,9 @@ protected List extends NodeFactory extends PythonBuiltinBaseNode>> getNodeFa
private static int findSlot(VirtualFrame frame, Node inliningTarget, PFrameLocalsProxy self, Object key, PyObjectRichCompareBool equals) {
BytecodeFrame bytecodeFrame = self.getBytecodeFrame();
BytecodeDSLFrameInfo info = (BytecodeDSLFrameInfo) bytecodeFrame.getFrameDescriptorInfo();
- for (int i = 0; i < info.getVariableCount(); i++) {
+ // Cell parameters occur in both varnames and cellvars. The function prologue moves their
+ // value to the cell slot and clears the regular slot, so prefer the later cell slot.
+ for (int i = info.getVariableCount() - 1; i >= 0; i--) {
if (equals.executeEq(frame, inliningTarget, info.getVariableName(i), key)) {
return i;
}
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 d93152e889..fb01ce9774 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
@@ -83,7 +83,6 @@
import com.oracle.graal.python.builtins.objects.PNotImplemented;
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
-import com.oracle.graal.python.builtins.objects.cell.PCell;
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;
@@ -387,11 +386,6 @@ static Object id(PString self,
return getObjectIdNode.execute(inliningTarget, self);
}
- @Specialization
- Object id(PCell self) {
- return PythonContext.get(this).getNextObjectId(self);
- }
-
protected static boolean isDefaultCase(PythonObject object) {
return !(object instanceof PBytes ||
object instanceof PFrozenSet ||
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 1b32d143f6..fdcd80ad66 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
@@ -140,6 +140,8 @@ public abstract class ErrorMessages {
public static final TruffleString BAD_MARSHAL_DATA_S = tsLiteral("bad marshal data (%s)");
public static final TruffleString BAD_MARSHAL_DATA_EOF = tsLiteral("marshal data too short");
public static final TruffleString BAD_MARSHAL_DATA_NULL = tsLiteral("bad NULL object in marshal data");
+ public static final TruffleString MARSHALLING_CODE_OBJECTS_DISALLOWED = tsLiteral("marshalling code objects is disallowed");
+ public static final TruffleString UNMARSHALLING_CODE_OBJECTS_DISALLOWED = tsLiteral("unmarshalling code objects is disallowed");
public static final TruffleString BAD_MEMBER_DESCR_TYPE_FOR_P = tsLiteral("bad memberdescr type for %p");
public static final TruffleString BAD_OPERAND_FOR = tsLiteral("bad operand type for %s%s: '%p'");
public static final TruffleString BAD_VALUES_IN_FDS_TO_KEEP = tsLiteral("bad value(s) in fds_to_keep");
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 89560c1427..faa93b972d 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
@@ -3382,7 +3382,7 @@ public static final class CreateCells {
public static void doCreateCells(VirtualFrame frame, LocalRangeAccessor locals,
@Bind PBytecodeDSLRootNode rootNode) {
for (int i = 0; i < locals.getLength(); i++) {
- PCell cell = new PCell(rootNode.cellEffectivelyFinalAssumptions[i]);
+ PCell cell = PFactory.createCell(rootNode.getLanguage(), rootNode.cellEffectivelyFinalAssumptions[i]);
locals.setObject(rootNode.getBytecodeNode(), frame, i, cell);
}
}
diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetClassNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetClassNode.java
index fa58519a8b..c90ac6c6d9 100644
--- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetClassNode.java
+++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetClassNode.java
@@ -44,7 +44,6 @@
import com.oracle.graal.python.builtins.objects.PNone;
import com.oracle.graal.python.builtins.objects.PNotImplemented;
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
-import com.oracle.graal.python.builtins.objects.cell.PCell;
import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes;
import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis;
@@ -194,11 +193,6 @@ static Object getNoDefault(@SuppressWarnings("unused") PNoDefault object) {
return PythonBuiltinClassType.PNoDefault;
}
- @Specialization
- static Object getCell(@SuppressWarnings("unused") PCell object) {
- return PythonBuiltinClassType.PCell;
- }
-
@InliningCutoff
@Specialization(guards = "isForeignObject(object)")
static Object getForeign(Object object,
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 8c9de7cc84..f2ffc12f91 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
@@ -833,8 +833,8 @@ public static PReferenceType createReferenceType(PythonLanguage language, Object
return new PReferenceType(cls, shape, object, callback, queue);
}
- public static PCell createCell(Assumption effectivelyFinal) {
- return new PCell(effectivelyFinal);
+ public static PCell createCell(PythonLanguage language, Assumption effectivelyFinal) {
+ return new PCell(PythonBuiltinClassType.PCell, PythonBuiltinClassType.PCell.getInstanceShape(language), effectivelyFinal);
}
/*
diff --git a/graalpython/graalpy-pyconfig/CMakeLists.txt b/graalpython/graalpy-pyconfig/CMakeLists.txt
index 13437d5c84..385a31faae 100644
--- a/graalpython/graalpy-pyconfig/CMakeLists.txt
+++ b/graalpython/graalpy-pyconfig/CMakeLists.txt
@@ -154,6 +154,7 @@ endif()
graalpy_sysconfig_env_value("LDCXXSHARED")
graalpy_sysconfig_env_value("LDSHARED")
graalpy_sysconfig_value("LDLIBRARY" "libpython.${GRAALPY_SYSCONFIG_SOABI}${GRAALPY_SYSCONFIG_SHLIB_SUFFIX}")
+graalpy_sysconfig_value("INSTSONAME" "${GRAALPY_SYSCONFIG_LDLIBRARY}")
set(GRAALPY_SYSCONFIG_STRING_NAMES
ABIFLAGS
@@ -166,6 +167,7 @@ set(GRAALPY_SYSCONFIG_STRING_NAMES
CXX
EXE
EXT_SUFFIX
+ INSTSONAME
LD
LDCXXSHARED
LDLIBRARY
diff --git a/graalpython/graalpy-pyconfig/_sysconfigdata_template.py b/graalpython/graalpy-pyconfig/_sysconfigdata_template.py
index 7db9c37367..6891aa0b7e 100644
--- a/graalpython/graalpy-pyconfig/_sysconfigdata_template.py
+++ b/graalpython/graalpy-pyconfig/_sysconfigdata_template.py
@@ -47,6 +47,7 @@
"CFLAGS_DEFAULT": "@GRAALPY_SYSCONFIG_CFLAGS_DEFAULT_PYTHON_STRING@",
"EXE": "@GRAALPY_SYSCONFIG_EXE_PYTHON_STRING@",
"EXT_SUFFIX": "@GRAALPY_SYSCONFIG_EXT_SUFFIX_PYTHON_STRING@",
+ "INSTSONAME": "@GRAALPY_SYSCONFIG_INSTSONAME_PYTHON_STRING@",
"LDLIBRARY": "@GRAALPY_SYSCONFIG_LDLIBRARY_PYTHON_STRING@",
"LDFLAGS": "@GRAALPY_SYSCONFIG_LDFLAGS_PYTHON_STRING@",
"LIBPYTHON": "",
diff --git a/graalpython/lib-graalpython/patches/cloudpickle-2.2.1.patch b/graalpython/lib-graalpython/patches/cloudpickle-2.2.1.patch
index e0c825cfef..0cf91ca051 100644
--- a/graalpython/lib-graalpython/patches/cloudpickle-2.2.1.patch
+++ b/graalpython/lib-graalpython/patches/cloudpickle-2.2.1.patch
@@ -2,10 +2,7 @@ diff --git a/cloudpickle/cloudpickle.py b/cloudpickle/cloudpickle.py
index 317be69..0c23e88 100644
--- a/cloudpickle/cloudpickle.py
+++ b/cloudpickle/cloudpickle.py
-@@ -512,10 +512,12 @@ def _walk_global_ops(code):
- """
- Yield referenced name for all global-referencing instructions in *code*.
- """
+@@ -515,4 +515,6 @@ def _walk_global_ops(code):
- for instr in dis.get_instructions(code):
- op = instr.opcode
- if op in GLOBAL_OPS:
@@ -16,6 +13,3 @@ index 317be69..0c23e88 100644
+ # op = instr.opcode
+ # if op in GLOBAL_OPS:
+ # yield instr.argval
-
-
- def _extract_class_dict(cls):
diff --git a/graalpython/lib-graalpython/patches/cython-3.2.4.patch b/graalpython/lib-graalpython/patches/cython-3.2.4.patch
index 648d6b5e40..2fa5ffd2a9 100644
--- a/graalpython/lib-graalpython/patches/cython-3.2.4.patch
+++ b/graalpython/lib-graalpython/patches/cython-3.2.4.patch
@@ -34,30 +34,60 @@ index 5ae2a4e..951aacc 100644
-watermark = str(version)
+watermark = f'{version}-graalpy'
diff --git a/Cython/Includes/cpython/array.pxd b/Cython/Includes/cpython/array.pxd
-index 4bc0438..72c0360 100644
+index 4bc0438..67dcff9 100644
--- a/Cython/Includes/cpython/array.pxd
+++ b/Cython/Includes/cpython/array.pxd
-@@ -133,7 +133,7 @@ cdef extern from *: # Hard-coded utility code hack.
+@@ -98,7 +98,10 @@ 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:
+@@ -133,8 +136,8 @@ cdef extern from *: # Hard-coded utility code hack.
PyObject_Free(info.shape)
array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr)
-
-+ array clonearray(object template_array, Py_ssize_t size)
__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'
-@@ -146,10 +146,7 @@ cdef inline array clone(array template, Py_ssize_t length, bint zero):
+ int resize(array self, Py_ssize_t n) except -1
+@@ -146,15 +149,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)
-- if zero and op is not None:
++ 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)
-- return op
-+ return clonearray(template, length)
++ 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:
+@@ -175,4 +181,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 8131c86..aa67eda 100644
--- a/Cython/Utility/CythonFunction.c
@@ -264,43 +294,51 @@ index b731f74..300758b 100644
return iterable;
#endif
diff --git a/Cython/Utility/arrayarray.h b/Cython/Utility/arrayarray.h
-index 2f7f0a5..b131885 100644
+index 2f7f0a5..ba32c0f 100644
--- a/Cython/Utility/arrayarray.h
+++ b/Cython/Utility/arrayarray.h
-@@ -106,6 +106,36 @@ PyObject* newarrayobject(PyTypeObject *type, Py_ssize_t size,
- struct arraydescr *descr);
- #endif /* ifndef NO_NEWARRAY_INLINE */
+@@ -23,7 +23,7 @@
+ // below. That's defined later because the appropriate get and set
+ // functions aren't visible yet.
+ typedef struct arraydescr {
+- int typecode;
++ char typecode;
+ int itemsize;
+ PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
+ int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
+@@ -64,10 +64,27 @@ struct arrayobject {
+ int ob_exports; /* Number of exported buffers */
+ };
-+static CYTHON_INLINE PyObject* clonearray(PyObject *template_array, Py_ssize_t size) {
-+#if CYTHON_COMPILING_IN_GRAAL
-+ PyObject* op = NULL;
-+ PyObject* module = NULL;
-+ PyObject* typecode = PyObject_GetAttrString(template_array, "typecode");
-+ if (typecode == NULL) {
-+ goto cleanup;
-+ }
-+ module = PyImport_ImportModule("array");
-+ if (module == NULL) {
-+ goto cleanup;
-+ }
-+ op = PyObject_CallMethod(module, "array", "O", typecode);
-+ if (op == NULL) {
-+ goto cleanup;
-+ }
-+ if (GraalPyArray_Resize(op, size) < 0) {
-+ Py_DECREF(op);
-+ op = NULL;
-+ }
-+cleanup:
-+ Py_XDECREF(typecode);
-+ Py_XDECREF(module);
-+ return op;
++#if CYTHON_COMPILING_IN_GRAAL && defined(GRAALPY_VERSION_NUM) && GRAALPY_VERSION_NUM >= 0x190304a0
++#define __PYX_USE_GRAALPY_ARRAY_API 1
+#else
-+ arrayobject *array = (arrayobject *) template_array;
-+ return newarrayobject(Py_TYPE(template_array), size, array->ob_descr);
++#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
+}
+
- static CYTHON_INLINE __Pyx_data_union __Pyx_PyArray_Data(arrayobject *self) {
- #if CYTHON_COMPILING_IN_GRAAL
- __Pyx_data_union data;
+ #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;
+
+@@ -100,6 +117,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/librt-0.10.0.patch b/graalpython/lib-graalpython/patches/librt-0.10.0.patch
index e3e7e555ee..43478c1d7c 100644
--- a/graalpython/lib-graalpython/patches/librt-0.10.0.patch
+++ b/graalpython/lib-graalpython/patches/librt-0.10.0.patch
@@ -89,6 +89,39 @@ index 6309ed5..2851067 100644
}
#define CPy_INCREF_NO_IMM(op) CPy_INCREF_NO_IMM((PyObject *)(op))
+diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h
+index 245050b..d04cb65 100644
+--- a/pythoncapi_compat.h
++++ b/pythoncapi_compat.h
+@@ -1576,7 +1576,7 @@ static inline int PyLong_IsZero(PyObject *obj)
+ // gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
+ #if PY_VERSION_HEX < 0x030E00A0
+
+-#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
++#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) && !defined(GRAALPY_VERSION_NUM)
+ PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
+ #endif
+
+@@ -1593,7 +1593,9 @@ static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
+ return -1;
+ }
+
+-#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
++#if defined(GRAALPY_VERSION_NUM)
++ return PyObject_RichCompareBool(str1, str2, Py_EQ);
++#elif PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
+ return _PyUnicode_Equal(str1, str2);
+ #elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
+ return _PyUnicode_EQ(str1, str2);
+@@ -2674,7 +2676,7 @@ PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op)
+ }
+ #endif
+
+-#if 0x030D0000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030F00A7 && !defined(PYPY_VERSION)
++#if 0x030D0000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030F00A7 && !defined(PYPY_VERSION) && !defined(GRAALPY_VERSION_NUM)
+ // Immortal objects were implemented in Python 3.12, however there is no easy API
+ // to make objects immortal until 3.14 which has _Py_SetImmortal(). Since
+ // immortal objects are primarily needed for free-threading, this API is implemented
diff --git a/pythonsupport.c b/pythonsupport.c
index 0a99f0a..1a442bb 100644
--- a/pythonsupport.c
@@ -142,10 +175,27 @@ index 0a99f0a..1a442bb 100644
// Slow path of CPyLong_AsSsize_tAndOverflow (non-inlined)
Py_ssize_t
diff --git a/pythonsupport.h b/pythonsupport.h
-index 6f38a9b..0e89511 100644
+index 6f38a9b..c636aec 100644
--- a/pythonsupport.h
+++ b/pythonsupport.h
-@@ -40,7 +40,15 @@ int init_subclass(PyTypeObject *type, PyObject *kwds);
+@@ -18,10 +18,16 @@
+ #ifndef Py_BUILD_CORE
+ #define Py_BUILD_CORE
+ #endif
++#ifdef GRAALPY_VERSION_NUM
++PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
++PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *);
++PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause(PyObject *, const char *, ...);
++#else
+ #include "internal/pycore_genobject.h" // _PyGen_FetchStopIterationValue
+ #include "internal/pycore_pyerrors.h" // _PyErr_FormatFromCause, _PyErr_SetKeyError
+ #include "internal/pycore_setobject.h" // _PySet_Update
+ #endif
++#endif
+
+ #if CPY_3_12_FEATURES
+ #include "internal/pycore_frame.h"
+@@ -40,7 +46,15 @@ int init_subclass(PyTypeObject *type, PyObject *kwds);
Py_ssize_t
CPyLong_AsSsize_tAndOverflow_(PyObject *vv, int *overflow);
@@ -162,7 +212,7 @@ index 6f38a9b..0e89511 100644
static inline Py_ssize_t
CPyLong_AsSsize_tAndOverflow(PyObject *vv, int *overflow)
-@@ -117,6 +125,7 @@ CPyLong_AsSsize_tAndOverflow(PyObject *vv, int *overflow)
+@@ -117,6 +131,7 @@ CPyLong_AsSsize_tAndOverflow(PyObject *vv, int *overflow)
#endif
// Adapted from listobject.c in Python 3.7.0
@@ -170,7 +220,7 @@ index 6f38a9b..0e89511 100644
static int
list_resize(PyListObject *self, Py_ssize_t newsize)
{
-@@ -162,6 +171,7 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
+@@ -162,6 +177,7 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
self->allocated = new_allocated;
return 0;
}
@@ -178,7 +228,7 @@ index 6f38a9b..0e89511 100644
// Changed to use PyList_SetSlice instead of the internal list_ass_slice
static PyObject *
-@@ -182,6 +192,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
+@@ -182,6 +198,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
return NULL;
}
v = PySequence_Fast_ITEMS((PyObject*)self)[index];
@@ -186,7 +236,7 @@ index 6f38a9b..0e89511 100644
if (index == Py_SIZE(self) - 1) {
status = list_resize(self, Py_SIZE(self) - 1);
if (status >= 0)
-@@ -189,6 +200,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
+@@ -189,6 +206,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
else
return NULL;
}
diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml
index cb1a98f320..3f19294db8 100644
--- a/graalpython/lib-graalpython/patches/metadata.toml
+++ b/graalpython/lib-graalpython/patches/metadata.toml
@@ -24,7 +24,7 @@ patch = 'cffi-1.16.0.patch'
license = 'MIT'
[[cloudpickle.rules]]
-version = '== 2.2.1'
+version = '>= 2.2.1'
patch = 'cloudpickle-2.2.1.patch'
license = 'BSD-3-Clause'
diff --git a/graalpython/lib-graalpython/patches/torch-2.10.0.patch b/graalpython/lib-graalpython/patches/torch-2.10.0.patch
index 4d4a2fccb3..1d82930f1d 100644
--- a/graalpython/lib-graalpython/patches/torch-2.10.0.patch
+++ b/graalpython/lib-graalpython/patches/torch-2.10.0.patch
@@ -767,7 +767,7 @@ index 6a8bbe990..d77fde704 100644
if (!m)
throw python_error();
diff --git a/torch/csrc/dynamo/cpython_defs.c b/torch/csrc/dynamo/cpython_defs.c
-index e0cb3bfe2..c98d75851 100644
+index e0cb3bfe2..d837740b9 100644
--- a/torch/csrc/dynamo/cpython_defs.c
+++ b/torch/csrc/dynamo/cpython_defs.c
@@ -28,6 +28,7 @@ void init_THPCaches() {}
@@ -787,19 +787,57 @@ index e0cb3bfe2..c98d75851 100644
// As a simple way to reduce the impact of ABI changes on the CPython side, this
// check forces us to manually re-check that the function didn't change on the
// next major version
-@@ -349,9 +352,11 @@ void THP_PyFrame_Clear(_PyInterpreterFrame* frame) {
+@@ -204,12 +207,15 @@ PyFrameObject* THP_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame* frame) {
+ // https://github.com/python/cpython/blob/e715da6db1d1d70cd779dc48e1ba8110c51cc1bf/Include/internal/pycore_frame.h#L163
+ static inline PyFrameObject* THP_PyFrame_GetFrameObject(
+ _PyInterpreterFrame* frame) {
++#if 0 // GraalPy change
+ CHECK(!_PyFrame_IsIncomplete(frame));
+ PyFrameObject* res = frame->frame_obj;
+ if (res != NULL) {
+ return res;
+ }
+ return THP_PyFrame_MakeAndSetFrameObject(frame);
++#endif // GraalPy change
++ abort();
+ }
+
+ #if IS_PYTHON_3_14_PLUS
+@@ -262,6 +268,7 @@ static void THP_take_ownership(PyFrameObject* f, _PyInterpreterFrame* frame) {
+ // From
+ // https://github.com/python/cpython/blob/e715da6db1d1d70cd779dc48e1ba8110c51cc1bf/Python/frame.c#L79
+ static void THP_take_ownership(PyFrameObject* f, _PyInterpreterFrame* frame) {
++#if 0 // GraalPy change
+ CHECK(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
+ CHECK(frame->owner != FRAME_CLEARED);
+ Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char*)frame;
+@@ -299,6 +306,8 @@ static void THP_take_ownership(PyFrameObject* f, _PyInterpreterFrame* frame) {
+ if (!PyObject_GC_IsTracked((PyObject*)f)) {
+ PyObject_GC_Track((PyObject*)f);
+ }
++#endif // GraalPy change
++ abort();
+ }
+
+ #endif
+@@ -347,6 +356,7 @@ void THP_PyFrame_Clear(_PyInterpreterFrame* frame) {
+ // From
+ // https://github.com/python/cpython/blob/e715da6db1d1d70cd779dc48e1ba8110c51cc1bf/Python/frame.c#L120
void THP_PyFrame_Clear(_PyInterpreterFrame* frame) {
++#if 0 // GraalPy change
/* It is the responsibility of the owning generator/coroutine
* to have cleared the enclosing generator, if any. */
-+#if 0 // GraalPy change
CHECK(
- frame->owner != FRAME_OWNED_BY_GENERATOR ||
- _PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED);
+@@ -382,6 +392,8 @@ void THP_PyFrame_Clear(_PyInterpreterFrame* frame) {
+ Py_DECREF(frame->f_func);
+ #endif
+ Py_DECREF(F_CODE(frame));
+#endif // GraalPy change
- // GH-99729: Clearing this frame can expose the stack (via finalizers). It's
- // crucial that this frame has been unlinked, and is no longer visible:
- #if IS_PYTHON_3_13_PLUS
-@@ -496,7 +501,7 @@ void THP_PyThreadState_PopFrame(
++ abort();
+ }
+
+ #endif
+@@ -496,7 +508,7 @@ void THP_PyThreadState_PopFrame(
const uint8_t* THP_PyOpcode_Caches = NULL;
int THP_PyOpcode_Caches_size = 0;
void init_THPCaches() {
diff --git a/graalpython/lib-python/3/dis.py b/graalpython/lib-python/3/dis.py
index 4b12037c06..49bf53fa53 100644
--- a/graalpython/lib-python/3/dis.py
+++ b/graalpython/lib-python/3/dis.py
@@ -5,27 +5,46 @@
import collections
import io
-# GraalPy change: remove all the _opcode imports and dependent stuff
-
-# GraalPy change: add dummy opcode metadata for coverage.py
-opmap = {
- "EXTENDED_ARG": -1,
- "JUMP_FORWARD": -1,
- "RETURN_VALUE": -1,
- "YIELD_VALUE": -1,
- "YIELD_FROM": -1,
-}
-opname = []
-hasjabs = []
-hasjrel = []
+# GraalPy change: expose the stub opcode metadata without importing _opcode
+from opcode import *
+from opcode import __all__ as _opcodes_all
__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
"findlinestarts", "findlabels", "show_code",
- "get_instructions", "Instruction", "Bytecode"]
+ "get_instructions", "Instruction", "Bytecode"] + _opcodes_all
+del _opcodes_all
_have_code = (types.MethodType, types.FunctionType, types.CodeType,
classmethod, staticmethod, type)
+CONVERT_VALUE = opmap['CONVERT_VALUE']
+
+SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE']
+FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')
+
+ENTER_EXECUTOR = opmap['ENTER_EXECUTOR']
+LOAD_CONST = opmap['LOAD_CONST']
+RETURN_CONST = opmap['RETURN_CONST']
+LOAD_GLOBAL = opmap['LOAD_GLOBAL']
+BINARY_OP = opmap['BINARY_OP']
+JUMP_BACKWARD = opmap['JUMP_BACKWARD']
+FOR_ITER = opmap['FOR_ITER']
+SEND = opmap['SEND']
+LOAD_ATTR = opmap['LOAD_ATTR']
+LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
+CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1']
+CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2']
+LOAD_FAST_LOAD_FAST = opmap['LOAD_FAST_LOAD_FAST']
+STORE_FAST_LOAD_FAST = opmap['STORE_FAST_LOAD_FAST']
+STORE_FAST_STORE_FAST = opmap['STORE_FAST_STORE_FAST']
+
+CACHE = opmap["CACHE"]
+
+_all_opname = list(opname)
+_all_opmap = dict(opmap)
+
+# GraalPy change
+deoptmap = {}
def _try_compile(source, name):
"""Attempts to compile the given source, first as an expression and
diff --git a/graalpython/lib-python/3/opcode.py b/graalpython/lib-python/3/opcode.py
index 5735686fa7..42d9a7532b 100644
--- a/graalpython/lib-python/3/opcode.py
+++ b/graalpython/lib-python/3/opcode.py
@@ -9,9 +9,7 @@
"HAVE_ARGUMENT", "EXTENDED_ARG", "hasarg", "hasconst", "hasname",
"hasjump", "hasjrel", "hasjabs", "hasfree", "haslocal", "hasexc"]
-import _opcode
-from _opcode import stack_effect
-
+# GraalPy change: remove _opcode import
from _opcode_metadata import (_specializations, _specialized_opmap, opmap,
HAVE_ARGUMENT, MIN_INSTRUMENTED_OPCODE)
EXTENDED_ARG = opmap['EXTENDED_ARG']
@@ -22,21 +20,26 @@
cmp_op = ('<', '<=', '==', '!=', '>', '>=')
+# GraalPy change: empty stub
+def stack_effect(opcode, oparg=None, /, *, jump=None):
+ raise NotImplementedError("'opcode' module is not supported on GraalPy")
+
+
# These lists are documented as part of the dis module's API
-hasarg = [op for op in opmap.values() if _opcode.has_arg(op)]
-hasconst = [op for op in opmap.values() if _opcode.has_const(op)]
-hasname = [op for op in opmap.values() if _opcode.has_name(op)]
-hasjump = [op for op in opmap.values() if _opcode.has_jump(op)]
+hasarg = []
+hasconst = []
+hasname = []
+hasjump = []
hasjrel = hasjump # for backward compatibility
hasjabs = []
-hasfree = [op for op in opmap.values() if _opcode.has_free(op)]
-haslocal = [op for op in opmap.values() if _opcode.has_local(op)]
-hasexc = [op for op in opmap.values() if _opcode.has_exc(op)]
+hasfree = []
+haslocal = []
+hasexc = []
-_intrinsic_1_descs = _opcode.get_intrinsic1_descs()
-_intrinsic_2_descs = _opcode.get_intrinsic2_descs()
-_nb_ops = _opcode.get_nb_ops()
+_intrinsic_1_descs = []
+_intrinsic_2_descs = []
+_nb_ops = []
hascompare = [opmap["COMPARE_OP"]]
diff --git a/mx.graalpython/downstream_tests.py b/mx.graalpython/downstream_tests.py
index e4948235b3..fe9982c230 100644
--- a/mx.graalpython/downstream_tests.py
+++ b/mx.graalpython/downstream_tests.py
@@ -117,9 +117,6 @@ def downstream_test_virtualenv(graalpy, testdir):
def downstream_test_pyo3(graalpy, testdir):
run(['git', 'clone', 'https://github.com/PyO3/pyo3.git', '-b', 'main', '--depth', '1'], cwd=testdir)
src = testdir / 'pyo3'
- # The runtime test session does not run mypy. Avoid installing it because its
- # librt dependency relies on CPython-internal APIs that are incompatible with GraalPy.
- replace_in_file(src / 'pytests/pyproject.toml', r'^\s*"mypy[^\n]*\n', '', flags=re.MULTILINE)
venv = src / 'venv'
run([graalpy, '-m', 'venv', str(venv)])
run_in_venv(venv, ['python', '-m', 'pip', 'install', '--upgrade', 'pip', 'nox[uv]'])
diff --git a/mx.graalpython/mx_graalpython_bisect.py b/mx.graalpython/mx_graalpython_bisect.py
index c696c806cc..f42f5f8213 100644
--- a/mx.graalpython/mx_graalpython_bisect.py
+++ b/mx.graalpython/mx_graalpython_bisect.py
@@ -305,10 +305,15 @@ def checkout(repo_path: Path, commit):
if repo_path == DIR:
mx.run_mx(['sforceimports'], suite=str(DIR))
if args.enterprise:
+ # Keep the Graal revision selected by the current bisection point. The
+ # enterprise suite imports Graal, so its sforceimports would otherwise
+ # replace that revision with the one recorded in graal-enterprise.
+ graal_commit = get_commit(GRAAL_DIR)
if repo_path.name != 'graal-enterprise':
mx.run_mx(['--quiet', 'checkout-downstream', 'vm', 'vm-enterprise', '--no-fetch'],
suite=str(VM_ENTERPRISE_DIR))
mx.run_mx(['--dy', 'substratevm-enterprise-gcs', 'sforceimports'], suite=str(VM_ENTERPRISE_DIR))
+ GIT.update_to_branch(GRAAL_DIR, graal_commit)
debug_str = f"debug: {SUITE.name}={get_commit(SUITE.vc_dir)} graal={get_commit(GRAAL_DIR)}"
if args.enterprise:
debug_str += f" graal-enterprise={get_commit(GRAAL_ENTERPRISE_DIR)}"
@@ -343,7 +348,7 @@ def checkout_and_build(repo_path, commit):
build_command = shlex.split(args.build_command)
if not args.no_clean:
try:
- clean_command = build_command[:build_command.index('build')] + ['clean']
+ clean_command = build_command[:build_command.index('build')] + ['clean', '--all', '--aggressive']
retcode = mx.run(clean_command, nonZeroIsFatal=False)
if retcode:
print("Warning: clean command failed")
diff --git a/scripts/bisect_benchmark_regression.py b/scripts/bisect_benchmark_regression.py
index 1207b5adbe..de28a01917 100644
--- a/scripts/bisect_benchmark_regression.py
+++ b/scripts/bisect_benchmark_regression.py
@@ -105,10 +105,17 @@ def parse_args() -> argparse.Namespace:
description="Generate and optionally submit a bisect-benchmark CI workflow for a benchmark regression.",
)
parser.add_argument("benchmark_job_name", help="Benchmark job key, for example pybench-micro-graalvm_ee_default-post_merge-linux-amd64-jdk-latest.")
- parser.add_argument("benchmark_name", help="Benchmark selector to narrow the benchmark command to a single benchmark.")
+ parser.add_argument("benchmark_name", help="Benchmark result name to bisect.")
parser.add_argument("metric", help="Benchmark metric name, or WORKS.")
parser.add_argument("good_commit", help="Known good GraalPy commit or ref.")
parser.add_argument("bad_commit", help="Known bad GraalPy commit or ref.")
+ parser.add_argument(
+ "--benchmark-selector",
+ help=(
+ "Benchmark selector used to narrow the benchmark command. Defaults to benchmark_name. "
+ "Use this when a harness selector produces several separately named results."
+ ),
+ )
parser.add_argument("--config-only", action="store_true", help="Print the generated bisect config and exit.")
parser.add_argument("--force-rebuild", action="store_true", help="Submit a fresh bisect job even if one already exists.")
parser.add_argument("--debug", action="store_true", help="Print progress information to stderr.")
@@ -153,16 +160,19 @@ def abbreviate_commit(commit: str) -> str:
return commit[:12]
-def build_branch_name(job_name: str, benchmark_name: str, metric: str, good_commit: str, bad_commit: str) -> str:
- slug = "_".join(
- [
- job_name,
- benchmark_name,
- metric,
- abbreviate_commit(good_commit),
- abbreviate_commit(bad_commit),
- ]
- )
+def build_branch_name(
+ job_name: str,
+ benchmark_name: str,
+ metric: str,
+ good_commit: str,
+ bad_commit: str,
+ benchmark_selector: str | None = None,
+) -> str:
+ parts = [job_name, benchmark_name]
+ if benchmark_selector:
+ parts.append(benchmark_selector)
+ parts.extend([metric, abbreviate_commit(good_commit), abbreviate_commit(bad_commit)])
+ slug = "_".join(parts)
return "bisect/{}".format(slug)
@@ -487,7 +497,7 @@ def write_temp_branch(repo_dir: Path, branch_name: str, config_text: str) -> str
run_command(["git", "add", *[str(path) for path in BRANCH_SUPPORT_FILES]], cwd=clone_dir)
run_command(["git", "commit", "-m", commit_message], cwd=clone_dir)
commit = resolve_commit(clone_dir, "HEAD")
- run_command(["git", "push", "origin", "HEAD:refs/heads/{}".format(branch_name)], cwd=clone_dir)
+ run_command(["git", "push", "--force", "origin", "HEAD:refs/heads/{}".format(branch_name)], cwd=clone_dir)
debug("Pushed branch {} at {}".format(branch_name, commit))
return commit
@@ -509,6 +519,7 @@ def generate_config(
repo_dir: Path,
benchmark_job_name: str,
benchmark_name: str,
+ benchmark_selector: str | None,
metric: str,
good_commit: str,
bad_commit: str,
@@ -516,7 +527,7 @@ def generate_config(
reference_build = get_reference_build(repo_dir, benchmark_job_name, bad_commit, good_commit)
debug("Using reference build {} ({})".format(reference_build.build_number, reference_build.url))
build_log = run_command(["gdev-cli", "buildbot", "get-log", str(reference_build.build_number)], cwd=repo_dir)
- build_command, benchmark_command = extract_commands(build_log, benchmark_name)
+ build_command, benchmark_command = extract_commands(build_log, benchmark_selector or benchmark_name)
results_benchmark_name = None if metric == "WORKS" else benchmark_selector_for_command(benchmark_name)
enterprise = "enterprise" in build_command
return build_config_text(
@@ -543,6 +554,7 @@ def main() -> int:
repo_dir=repo_dir,
benchmark_job_name=args.benchmark_job_name,
benchmark_name=args.benchmark_name,
+ benchmark_selector=args.benchmark_selector,
metric=args.metric,
good_commit=good_commit,
bad_commit=bad_commit,
@@ -558,11 +570,12 @@ def main() -> int:
args.metric,
good_commit,
bad_commit,
+ args.benchmark_selector,
)
debug("Branch name: {}".format(branch_name))
branch_head = get_remote_branch_head(repo_dir, branch_name)
- if branch_head is None:
+ if branch_head is None or args.force_rebuild:
branch_head = write_temp_branch(repo_dir, branch_name, config_text)
wait_for_enumeration(
repo_dir,
@@ -577,7 +590,7 @@ def main() -> int:
else:
debug("Remote branch head: {}".format(branch_head))
existing_builds = get_matching_builds(repo_dir, branch_head, BISECT_JOB_NAME)
- if existing_builds and not args.force_rebuild:
+ if existing_builds:
build = wait_for_bisect_build(repo_dir, branch_head)
else:
wait_for_enumeration(
diff --git a/scripts/get_pypi_source.py b/scripts/get_pypi_source.py
index 06a9d07d73..50f50ff306 100755
--- a/scripts/get_pypi_source.py
+++ b/scripts/get_pypi_source.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python3
# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
@@ -37,8 +38,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-#!/usr/bin/python
-
import argparse
import builtins
import json