Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate LOAD_ATTR+CALL_FUNCTION instead of LOAD_METHOD+CALL_METHOD for imports #88479

Closed
isidentical opened this issue Jun 4, 2021 · 5 comments
Assignees
Labels
3.11 bug and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)

Comments

@isidentical
Copy link
Sponsor Member

BPO 44313
Nosy @markshannon, @corona10, @isidentical
PRs
  • bpo-44313: generate LOAD_ATTR/CALL_FUNCTION for top-level imported objects #26677
  • bpo-44313: bump up the magic number after compiler changes #26983
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/isidentical'
    closed_at = <Date 2021-07-01.07:53:42.862>
    created_at = <Date 2021-06-04.16:33:18.716>
    labels = ['interpreter-core', '3.11']
    title = 'Generate LOAD_ATTR+CALL_FUNCTION instead of LOAD_METHOD+CALL_METHOD for imports'
    updated_at = <Date 2021-07-01.19:25:38.369>
    user = 'https://github.com/isidentical'

    bugs.python.org fields:

    activity = <Date 2021-07-01.19:25:38.369>
    actor = 'BTaskaya'
    assignee = 'BTaskaya'
    closed = True
    closed_date = <Date 2021-07-01.07:53:42.862>
    closer = 'BTaskaya'
    components = ['Interpreter Core']
    creation = <Date 2021-06-04.16:33:18.716>
    creator = 'BTaskaya'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 44313
    keywords = ['patch']
    message_count = 5.0
    messages = ['395099', '395103', '395516', '396802', '396826']
    nosy_count = 3.0
    nosy_names = ['Mark.Shannon', 'corona10', 'BTaskaya']
    pr_nums = ['26677', '26983']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue44313'
    versions = ['Python 3.11']

    @isidentical
    Copy link
    Sponsor Member Author

    import foo
    def func():
        return foo.bar()

    The snippet above will generate the following code;

    2 0 LOAD_GLOBAL 0 (foo)
    2 LOAD_METHOD 1 (bar)
    4 CALL_METHOD 0
    6 RETURN_VALUE

    Though this will make things harder for specializing the LOAD_ATTR for modules since now the handling of LOAD_METHOD for that case is necessary so for the imports that we can infer during the symbol analysis pass, we'll generate LOAD_ATTR+CALL_ATTR instead of LOAD_METHOD+CALL_METHOD and hopefully the generated code will get specialized via the PEP-659.

    Ref: faster-cpython/ideas#55 (comment)

    @isidentical isidentical added the 3.11 bug and security fixes label Jun 4, 2021
    @isidentical isidentical self-assigned this Jun 4, 2021
    @isidentical isidentical added interpreter-core (Objects, Python, Grammar, and Parser dirs) 3.11 bug and security fixes labels Jun 4, 2021
    @isidentical isidentical self-assigned this Jun 4, 2021
    @isidentical isidentical added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Jun 4, 2021
    @isidentical
    Copy link
    Sponsor Member Author

    @mark.shannon what do you think about doing this both for import <module> and from <module> import <something>. It will definitely simplify the implementation (no need to extra visitors or flags, just using the default DEF_IMPORT one isidentical@f8f8fce) and also might help you to specialize other cases too (e.g importing submodules, from concurrent import futures).

    @markshannon
    Copy link
    Member

    Yes. Simpler is good.

    I think it will also be better for performance:

    In general, we don't know what X is in from Y import X. It could be a module or anything else.

    However, if we are accessing an attribute it is quite likely to be a module or class.
    For X defined by from Y import X, X is likely to be a module, class, function, or some sort of constant like a string, int or Enum.

    If it is a string, int or function then it is rare to call a method on it, so we can ignore that case.
    Calling methods on an Enum constant is probably not very common either (I'm guessing here)

    For a module, LOAD_ATTR; CALL_FUNCTION is clearly better than LOAD_METHOD; CALL_METHOD.

    For a class, specializing LOAD_ATTR is no more complex than LOAD_METHOD, probably simpler.
    So, for a class LOAD_ATTR; CALL_FUNCTION is no worse than LOAD_METHOD; CALL_METHOD, and might be better.

    Overall, it looks like X.foo() when X is defiend by from Y import X is best as LOAD_ATTR; CALL_FUNCTION not LOAD_METHOD; CALL_METHOD.

    @markshannon
    Copy link
    Member

    New changeset 1b28187 by Batuhan Taskaya in branch 'main':
    bpo-44313: generate LOAD_ATTR/CALL_FUNCTION for top-level imported objects (GH-26677)
    1b28187

    @isidentical
    Copy link
    Sponsor Member Author

    New changeset 0d7f61d by Batuhan Taskaya in branch 'main':
    bpo-44313: bump up magic (bpo-26983)
    0d7f61d

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 bug and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants