Skip to content

Conversation

@brandtbucher
Copy link
Member

@brandtbucher brandtbucher commented Apr 8, 2025

CALL_TYPE_1, CALL_STR_1, CALL_TUPLE_1, CALL_LEN, and CALL_ISINSTANCE will never call a method descriptor, which means that we can just assert that self_or_null is NULL instead of checking and "adjusting" the arguments each time.

CALL_BUILTIN_CLASS should never call a method descriptor, but I'm not sure that we can gurantee it. So I've just made this a DEOPT_IF instead.

@brandtbucher brandtbucher added performance Performance or resource usage interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Apr 8, 2025
@brandtbucher brandtbucher self-assigned this Apr 8, 2025
@markshannon
Copy link
Member

What about this:

def call_x(a, b):
    return a.x(b)
class C: pass
c = C()
c.x = type
call_x(c, 1); call_x(c, 1)
f = types.MethodType(type, 3)
class D:
    x = f
d = D()
call_x(d, "string")

@brandtbucher
Copy link
Member Author

I'll try, but I'm pretty sure those are fine, since LOAD_ATTR only performs the "unwrapping" optimization for method descriptors (type, str, tuple, len, isisinstance, and types.MethodType aren't).

At any rate, I'll add a test.

@brandtbucher
Copy link
Member Author

@markshannon, I went ahead and added a bunch of tests for weird method patterns like that.

@markshannon
Copy link
Member

I'm still reluctant to make this change, as it makes the behavior of individual instructions depend on implicit context.
For example, this function:

def f(x, a, b):
     return x(a, b)

currently compiles as

  1           RESUME                   0

  2           LOAD_FAST_BORROW         0 (x)
              PUSH_NULL
              LOAD_FAST_BORROW_LOAD_FAST_BORROW 18 (a, b)
              CALL                     2
              RETURN_VALUE

but it could be correctly compiled as:

  1           RESUME                   0

  2           LOAD_FAST_BORROW         0 (x)
              LOAD_FAST_BORROW_LOAD_FAST_BORROW 18 (a, b)
              CALL                     1
              RETURN_VALUE

which would not work with this PR.

@markshannon
Copy link
Member

IIRC, we use do just something like that. When compiling m.f(...) if m was defined by an import we would use LOAD_ATTR instead of LOAD_METHOD, so that m.f(a, b) would compile to the then equivalent of CALL 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review interpreter-core (Objects, Python, Grammar, and Parser dirs) performance Performance or resource usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants