Title: Why do we have two counters for function versions? · Issue #116916 · python/cpython · GitHub
Open Graph Title: Why do we have two counters for function versions? · Issue #116916 · python/cpython
X Title: Why do we have two counters for function versions? · Issue #116916 · python/cpython
Description: In the interpreter state there are two separate counters that are used to generate unique versions for code and function objects. Both counters share the following properties: The counter is an unsigned 32-bit int initialized to 1 When a...
Open Graph Description: In the interpreter state there are two separate counters that are used to generate unique versions for code and function objects. Both counters share the following properties: The counter is an uns...
X Description: In the interpreter state there are two separate counters that are used to generate unique versions for code and function objects. Both counters share the following properties: The counter is an uns...
Opengraph URL: https://github.com/python/cpython/issues/116916
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Why do we have two counters for function versions?","articleBody":"In the interpreter state there are two separate counters that are used to generate unique versions for code and function objects. Both counters share the following properties:\r\n- The counter is an unsigned 32-bit int initialized to `1`\r\n- When a new version is needed, the current value of the counter is used, and unless the counter is zero, the counter is incremented\r\n- When the counter overflows to `0`, it remains zero, and no new versions can be allocated (in this case the specializer will just give up -- hopefully this never happens in real code, creating four billion code objects is just hard to imagine)\r\n\r\nThere are two ways that a **function object** obtains a version:\r\n- The usual path is when a function object is created by the `MAKE_FUNCTION` bytecode. In this case it gets the version from the code object. (See below.)\r\n- When an assignment is made to `func.__code__` or a few other attributes, the function version is reset, and if the specializer later needs a function version, a new version number is taken from `interp-\u003efunc_state.next_version` by `_PyFunction_GetVersionForCurrentState()`. \r\n\r\nCode objects obtain a version when they are created from `interp-\u003enext_func_version`.\r\n\r\nI believe there's a scenario where two unrelated function objects could end up with the same version:\r\n- one function is created with a version derived from its code object, i.e. from `interp-\u003enext_func_version`;\r\n- the other has had its `__code__` attribute modified, and then obtains a fresh version from `interp-\u003efunc_state.next_version`, which somehow has the same value as the other counter had -- this should be possible because the counters are managed independently.\r\n\r\nI looked a bit into the history, and it looks like in 3.11 there was only a static global `next_func_version` in funcobject.c, which was used by `_PyFunction_GetVersionForCurrentState()`. In 3.12 the current structure exists, except `next_func_version` is still a static global (`func_state` however is an interpreter member). It seems that this was introduced by gh-98525 (commit: https://github.com/python/cpython/commit/fb713b21833a17cba8022af0fa4c486512157d4b). Was it intentional to use two separate counters? If so, what was the rationale? (If it had to do with deepfreeze, that rationale is now gone, as we no longer use it.)\r\n\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-116918\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/gvanrossum","@type":"Person","name":"gvanrossum"},"datePublished":"2024-03-16T21:11:32.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1},"url":"https://github.com/116916/cpython/issues/116916"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:631a063c-e7b5-3e70-fe65-30e6f5b2a235 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | BA38:3A3C76:35EE2F2:4D05045:6A568E57 |
| html-safe-nonce | b195436029cf8b50b5f13fa0a345dfd0fb4f929b86a398beab2312e114df1c48 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCQTM4OjNBM0M3NjozNUVFMkYyOjREMDUwNDU6NkE1NjhFNTciLCJ2aXNpdG9yX2lkIjoiNTUzMzMyMjY1MDA0MjA3NzA0IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | fe3dc76d60583bb744f73ee398719e2b489ef2ee24818b1a4a7ce7a860fb38ee |
| hovercard-subject-tag | issue:2190252218 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/116916/issue_layout |
| twitter:image | https://opengraph.githubassets.com/32ca3c7b1b7a29e1f46309e9321791eda8839fe8434f15b37d388f71a0cf3b03/python/cpython/issues/116916 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/32ca3c7b1b7a29e1f46309e9321791eda8839fe8434f15b37d388f71a0cf3b03/python/cpython/issues/116916 |
| og:image:alt | In the interpreter state there are two separate counters that are used to generate unique versions for code and function objects. Both counters share the following properties: The counter is an uns... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | gvanrossum |
| hostname | github.com |
| expected-hostname | github.com |
| None | 8f21be8503ba8fe6154df415b855c03af52eae3f285bd6ae1fef041dc053da38 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 78af172a48a2056810bb627ffa684003e4f9a5ca |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width