GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — bpo-43693: Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. by ericsnowcurrently · Pull Request #26388 · python/cpython

Conversation

@ericsnowcurrently

@ericsnowcurrently ericsnowcurrently commented May 26, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

A number of places in the code base (notably ceval.c and frameobject.c) rely on mapping variable names to indices in the frame "locals plus" array (AKA fast locals), and thus opargs. Currently the compiler indirectly encodes that information on the code object as the tuples co_varnames, co_cellvars, and co_freevars. At runtime the dependent code must calculate the proper mapping from those, which isn't ideal and impacts performance-sensitive sections. This is something we can easily address in the compiler instead.

This PR addresses the situation by replacing internal use of co_varnames, etc. with a single combined tuple of names in locals-plus order, along with a minimal array mapping each to its kind (local vs. cell vs. free). These two new PyCodeObject fields, co_fastlocalnames and co_fastllocalkinds, are not exposed to Python code for now, but co_varnames, etc. are still available with the same values as before (though computed lazily).

Aside from the (mild) performance impact, there are a number of other benefits:

  • there's now a clear, direct relationship between locals-plus and variables
  • code that relies on the locals-plus-to-name mapping is simpler
  • marshaled code objects are smaller and serialize/de-serialize faster

Also note that we can take this approach further by expanding the possible values in co_fastlocalkinds to include specific argument types (e.g. positional-only, kwargs). Doing so would allow further speed-ups in _PyEval_MakeFrameVector(), which is where args get unpacked into the locals-plus array. It would also allow us to shrink marshaled code objects even further.

(FYI, I have a later PR that relies on having this direct mapping instead of co_varnames.)

FWIW, if this PR is too big I can split it up between "add the fields" and "use the fields". However, typically in this project we keep those together in one change.

https://bugs.python.org/issue43693

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ericsnowcurrently
ericsnowcurrently requested a review from markshannon May 26, 2021 20:08
@ericsnowcurrently
ericsnowcurrently requested a review from tiran as a code owner May 26, 2021 20:08
@the-knights-who-say-ni the-knights-who-say-ni added the CLA signed label May 26, 2021
@bedevere-bot bedevere-bot added the awaiting core review label May 26, 2021
@ericsnowcurrently
ericsnowcurrently removed the request for review from tiran May 26, 2021 20:11
@ericsnowcurrently
ericsnowcurrently force-pushed the fast-local-kinds branch from af397af to fda53f1 Compare May 26, 2021 22:55
This was referenced May 27, 2021
bpo-43693: Add the MAKE_CELL opcode and interleave fast locals offsets. #26396
Merged
Handle boxing of cell variables in the bytecode. faster-cpython/ideas#41
Closed
markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Include/cpython/code.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Include/internal/pycore_code.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Include/internal/pycore_code.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Objects/codeobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Objects/codeobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Objects/frameobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

markshannon
markshannon reviewed May 27, 2021
View reviewed changes
Comment thread Objects/typeobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently
ericsnowcurrently force-pushed the fast-local-kinds branch from c95f4cc to 0d1d6cd Compare May 27, 2021 15:59
@markshannon markshannon self-assigned this May 28, 2021
@markshannon

markshannon commented May 28, 2021

Copy link
Copy Markdown
Member

Some thoughts on the API.

I don't like the word "fast". It has no meaning and just makes names longer. I'd much prefer "variables" to "fastlocals".
The point of your refactoring was to hide implementation details, but by exposing things like the arrays of locals and kinds we are just exposing different ones.

So I was thinking...
What is the use case for accessing this data? Presumably debuggers, profilers and dis.
Would it not be more useful for them to be able to query the metadata, rather than having to parse it?
E.g. (and this is just off the top of my head)

class CodeType:
     def get_variable_name(self, n:int):
           "Return the names of the nth variable"
     def get_variable_scope(self, n:int):
           "Returns the scope of the nth var (one of LOCAL, ESCAPES, FREE)"
     def get_variable_kind(self, n:int):
           "Return the kind of nth var (one of LOCAL, ARG, VARARG, etc)"

or

class CodeType:
     def get_variable_metadata(self, n:int):
          "Returns a triple (name, scope, kind) for nth variable"

What do you think?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

gvanrossum
gvanrossum reviewed May 28, 2021
View reviewed changes

@gvanrossum gvanrossum left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple drive-by comments.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Doc/library/dis.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Include/internal/pycore_code.h Resolved

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented May 28, 2021

Copy link
Copy Markdown
Member

I don't like the word "fast". It has no meaning and just makes names longer. I'd much prefer "variables" to "fastlocals".

Yeah, they were fast several decades ago when this was an improvement over storing locals in a dict. :-) But it's a traditional name, and changing it would just add a bunch of additional unneeded churn (e.g. we have LOAD_FAST etc. -- to be consistent you'd have to rename those too).

Plus, these locals really are pretty fast. :-)

[...]

Would it not be more useful for them to be able to query the metadata, rather than having to parse it?

At least some debuggers access this data in C, so we'd have to introduce C API functions as well. I don't think we'll actually be able to come up with abstractions that won't have to change if this stuff changes again in the future.

I think that at least for this PR, we should leave well enough alone -- at some point in the future, co_fastlocalnames and friends will be presumably lazily computed, at least when accessed from Python code (e.g. pdb, dis).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markshannon

markshannon commented May 28, 2021

Copy link
Copy Markdown
Member

If the abstraction models the language, then it shouldn't need to change (unless the language does).

The scope (local, escapes, or free), the kind (arg, kwarg, non-arg, etc), and the name are all properties of the variable and independent of the data structures used.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gvanrossum

gvanrossum commented May 28, 2021 via email

Copy link
Copy Markdown
Member
Yeah, let's make sure to settle this API once we're farther along, but within the 3.11 timeframe.
ericsnowcurrently reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markshannon

markshannon commented May 29, 2021

Copy link
Copy Markdown
Member

Why not do it now? What is the advantage of exposing things to hide them later.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jun 2, 2021

Copy link
Copy Markdown
Member Author

Some thoughts on the API.

[...]

What do you think?

I'm fine with taking a more neutral approach, along the lines you suggested. However, I don't want to introduce a new public API (in Python or in C) in this PR.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jun 2, 2021

Copy link
Copy Markdown
Member Author

@markshannon, please take another look at this PR when you get the chance.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markshannon

markshannon commented Jun 3, 2021

Copy link
Copy Markdown
Member

Windows warnings need fixing: https://github.com/python/cpython/pull/26388/files#diff-ebc983d9f91e5bcf73500e377ac65e85863c4f77fd5b6b6caf4fcdf7c0f0b057R7253

You say that you don't want to add a public API, but that is what you are doing by adding co_fastlocalnames and co_fastlocalkinds.
I'd rather that we added the API first then changed the implementation behind that API, but to get things moving can you just make the attributes "private" by prefixing them with an underscore?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently

ericsnowcurrently commented Jun 3, 2021

Copy link
Copy Markdown
Member Author

You say that you don't want to add a public API, but that is what you are doing by adding co_fastlocalnames and co_fastlocalkinds.
I'd rather that we added the API first then changed the implementation behind that API, but to get things moving can you just make the attributes "private" by prefixing them with an underscore?

You mean the fields on the struct? I was talking about the attributes exposed to Python code. As far as the struct goes, I'm fine with adding an underscore prefix but I don't see the point since using the fields is required and given the class of expected users. I'd rather make PyCodeObject opaque in the public C-API (moving it to Include/internal/pycore_code.h), but that is a separate matter.

In the meantime I will add an undercore prefix to those fields so we can move this along.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@markshannon

markshannon commented Jun 3, 2021

Copy link
Copy Markdown
Member

I meant the Python attributes, but it looks like you've already removed them 👍

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently
ericsnowcurrently force-pushed the fast-local-kinds branch from 9dcd35d to fdf040a Compare June 3, 2021 15:52
@ericsnowcurrently
Add co_fastlocalnames and co_fastlocalkinds.
a5edf53
ericsnowcurrently added 15 commits June 3, 2021 09:57
@ericsnowcurrently
Update the dis docs.
9de74bd
@ericsnowcurrently
Use co_fastlocalnames in the dis module.
e50e286
@ericsnowcurrently
Fix some comments.
f0fda39
@ericsnowcurrently
Drop "inline" from some big functions.
361ca0a
@ericsnowcurrently
Clarify that we only look through the free vars in super_init_without…
bbdaada
…_args().
@ericsnowcurrently
Clarify about the case where a "fast" arg is also a cell.
8c100d9
@ericsnowcurrently
Use a private getter function for co_fastlocalnames instead of a prop…
505536e
…erty.
@ericsnowcurrently
Drop the arg-related flags.
885e435
@ericsnowcurrently
Leave the bottom numbers for locals kinds.
29e1c2a
@ericsnowcurrently
"fastlocal" -> "localsplus"
235e4aa
@ericsnowcurrently
Add a note about "locals plus" and variable kinds.
13fe60d
@ericsnowcurrently
co._get_localsplusnames() -> co._varname_from_oparg()
fba56f5
@ericsnowcurrently
Fix the gdb hooks.
68c7776
@ericsnowcurrently
Be more strict about types.
e10e7da
@ericsnowcurrently
Add a TODO about "_PyCodeConstructor.argcount".
87cb192
@ericsnowcurrently
ericsnowcurrently force-pushed the fast-local-kinds branch from fdf040a to 87cb192 Compare June 3, 2021 15:59
@ericsnowcurrently

ericsnowcurrently commented Jun 3, 2021

Copy link
Copy Markdown
Member Author

Thanks, @markshannon!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ericsnowcurrently
ericsnowcurrently merged commit 2c1e258 into python:main Jun 3, 2021
@bedevere-bot bedevere-bot removed the awaiting core review label Jun 3, 2021
@ericsnowcurrently
ericsnowcurrently deleted the fast-local-kinds branch June 3, 2021 16:28
pablogsal added a commit to pablogsal/cpython that referenced this pull request Jun 4, 2021
@pablogsal
Revert "bpo-43693: Add new internal code objects fields: co_fastlocal…
9b5f708
…names and co_fastlocalkinds. (pythongh-26388)"

This reverts commit 2c1e258.
pablogsal added a commit that referenced this pull request Jun 4, 2021
@pablogsal
bpo-43693: Revert commits 2c1e258 and b2bf2bc (GH-26530)
17c4edc
* Revert "bpo-43693: Compute deref offsets in compiler (gh-25152)"

This reverts commit b2bf2bc.

* Revert "bpo-43693: Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388)"

This reverts commit 2c1e258.

These two commits are breaking the refleak buildbots.
@ericsnowcurrently ericsnowcurrently mentioned this pull request Jun 7, 2021
bpo-43693: Un-revert commits 2c1e258 and b2bf2bc. #26577
Merged
ericsnowcurrently added a commit to ericsnowcurrently/cpython that referenced this pull request Jun 7, 2021
@ericsnowcurrently
Un-revert commits 2c1e258 and b2bf2bc.
5e98b69
These were reverted in pythonGH-26530 (commit 17c4edc).

* Compute deref offsets in compiler (pythongh-25152)
* Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (pythongh-26388)
ericsnowcurrently added a commit that referenced this pull request Jun 7, 2021
@ericsnowcurrently
bpo-43693: Un-revert commits 2c1e258 and b2bf2bc. (gh-26577)
2ab27c4
These were reverted in gh-26530 (commit 17c4edc) due to refleaks.

* 2c1e258 - Compute deref offsets in compiler (gh-25152)
* b2bf2bc - Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388)

This change fixes the refleaks.

https://bugs.python.org/issue43693
@markshannon markshannon mentioned this pull request May 2, 2022
Logically merge cell and locals array. They are already contiguous in memory #87859
Closed
iritkatriel
iritkatriel reviewed Jun 28, 2022
View reviewed changes
Comment thread Python/compile.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@hugovk hugovk mentioned this pull request Mar 13, 2023
Docs: Description of LOAD_CLOSURE in dis module should be updated #102636
Closed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 17, 2026
typedef parity: code/function/method/cell/property/class/staticmethod (3.14) pyre-lang/pyre#610
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@iritkatriel iritkatriel iritkatriel left review comments
@gvanrossum gvanrossum gvanrossum left review comments
@markshannon markshannon markshannon left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@markshannon markshannon

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@ericsnowcurrently @markshannon @gvanrossum @iritkatriel @the-knights-who-say-ni @bedevere-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.