Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ extern int _PyObject_IsInstanceDictEmpty(PyObject *);

// Export for 'math' shared extension
PyAPI_FUNC(PyObject*) _PyObject_LookupSpecial(PyObject *, PyObject *);
PyAPI_FUNC(PyObject*) _PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null);
PyAPI_FUNC(int) _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self);

// Calls the method named `attr` on `self`, but does not set an exception if
// the attribute does not exist.
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Include/internal/pycore_uop_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 24 additions & 19 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2774,32 +2774,37 @@ _PyObject_LookupSpecial(PyObject *self, PyObject *attr)
return res;
}

/* Steals a reference to self */
PyObject *
_PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null)
// Lookup the method name `attr` on `self`. On entry, `method_and_self[0]`
// is null and `method_and_self[1]` is `self`. On exit, `method_and_self[0]`
// is the method object and `method_and_self[1]` is `self` if the method is
// not bound.
// Return 0 on success, -1 on error or if the method is missing.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment needs to be updated.

int
_PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self)
{
PyObject *res;

res = _PyType_LookupRef(Py_TYPE(self), attr);
if (res == NULL) {
Py_DECREF(self);
*self_or_null = NULL;
return NULL;
PyObject *self = PyStackRef_AsPyObjectBorrow(method_and_self[1]);
_PyType_LookupStackRefAndVersion(Py_TYPE(self), attr, &method_and_self[0]);
PyObject *method_o = PyStackRef_AsPyObjectBorrow(method_and_self[0]);
if (method_o == NULL) {
return 0;
}

if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
if (_PyType_HasFeature(Py_TYPE(method_o), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
/* Avoid temporary PyMethodObject */
*self_or_null = self;
return 1;
}
else {
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
if (f != NULL) {
Py_SETREF(res, f(res, self, (PyObject *)(Py_TYPE(self))));

descrgetfunc f = Py_TYPE(method_o)->tp_descr_get;
if (f != NULL) {
PyObject *func = f(method_o, self, (PyObject *)(Py_TYPE(self)));
if (func == NULL) {
return -1;
}
*self_or_null = NULL;
Py_DECREF(self);
PyStackRef_CLEAR(method_and_self[0]); // clear method
method_and_self[0] = PyStackRef_FromPyObjectSteal(func);
}
return res;
PyStackRef_CLEAR(method_and_self[1]); // clear self
return 1;
}

static int
Expand Down
28 changes: 13 additions & 15 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3365,23 +3365,21 @@ dummy_func(
_FOR_ITER_GEN_FRAME +
_PUSH_FRAME;

inst(LOAD_SPECIAL, (owner -- attr, self_or_null)) {
assert(oparg <= SPECIAL_MAX);
PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner);
inst(LOAD_SPECIAL, (self -- method_and_self[2])) {
method_and_self[1] = self;
method_and_self[0] = PyStackRef_NULL;
DEAD(self);
PyObject *name = _Py_SpecialMethods[oparg].name;
PyObject *self_or_null_o;
PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o);
if (attr_o == NULL) {
if (!_PyErr_Occurred(tstate)) {
_PyErr_Format(tstate, PyExc_TypeError,
_Py_SpecialMethods[oparg].error,
Py_TYPE(owner_o)->tp_name);
}
ERROR_IF(true, error);
int err = _PyObject_LookupSpecialMethod(name, method_and_self);
if (err < 0) {
ERROR_NO_POP();
}
else if (err == 0) {
_PyErr_Format(tstate, PyExc_TypeError,
_Py_SpecialMethods[oparg].error,
PyStackRef_TYPE(method_and_self[1])->tp_name);
ERROR_NO_POP();
}
attr = PyStackRef_FromPyObjectSteal(attr_o);
self_or_null = self_or_null_o == NULL ?
PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o);
}

inst(WITH_EXCEPT_START, (exit_func, exit_self, lasti, unused, val -- exit_func, exit_self, lasti, unused, val, res)) {
Expand Down
37 changes: 16 additions & 21 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 16 additions & 21 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions Tools/ftscalingbench/ftscalingbench.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ def object_lookup_special():
for i in range(N):
round(i / N)

class MyContextManager:
def __enter__(self):
pass
def __exit__(self, exc_type, exc_value, traceback):
pass

@register_benchmark
def context_manager():
N = 1000 * WORK_SCALE
for i in range(N):
with MyContextManager():
pass

@register_benchmark
def mult_constant():
x = 1.0
Expand Down
Loading