Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
35 changes: 18 additions & 17 deletions Include/opcode.h

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

1 change: 1 addition & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def jabs_op(name, op):
"LOAD_ATTR_WITH_HINT",
"LOAD_ATTR_SLOT",
"LOAD_ATTR_MODULE",
"LOAD_ATTR_CLASS",
"LOAD_GLOBAL_ADAPTIVE",
"LOAD_GLOBAL_MODULE",
"LOAD_GLOBAL_BUILTIN",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve ``LOAD_METHOD_CLASS`` specialization by adding more specialized
forms.
38 changes: 25 additions & 13 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,21 @@ eval_frame_handle_pending(PyThreadState *tstate)
STAT_INC(LOAD_##attr_or_method, hit); \
Py_INCREF(res);

// shared by LOAD_ATTR_CLASS and LOAD_METHOD_CLASS
#define LOAD_CLASS_ATTR_OR_METHOD(attr_or_method) \
SpecializedCacheEntry *caches = GET_CACHE(); \
_PyAttrCache *cache1 = &caches[-1].attr; \
_PyObjectCache *cache2 = &caches[-2].obj; \
DEOPT_IF(!PyType_Check(cls), LOAD_##attr_or_method); \
DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != cache1->tp_version, \
LOAD_##attr_or_method); \
assert(cache1->tp_version != 0); \
STAT_INC(LOAD_##attr_or_method, hit); \
PyObject *res = cache2->obj; \
assert(res != NULL); \
Py_INCREF(res); \


static int
trace_function_entry(PyThreadState *tstate, InterpreterFrame *frame)
{
Expand Down Expand Up @@ -3748,6 +3763,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
DISPATCH();
}

TARGET(LOAD_ATTR_CLASS) {
assert(cframe.use_tracing == 0);
PyObject *cls = TOP();
LOAD_CLASS_ATTR_OR_METHOD(ATTR);
SET_TOP(res);
Py_DECREF(cls);
DISPATCH();
}

TARGET(STORE_ATTR_ADAPTIVE) {
assert(cframe.use_tracing == 0);
SpecializedCacheEntry *cache = GET_CACHE();
Expand Down Expand Up @@ -4554,20 +4578,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(LOAD_METHOD_CLASS) {
/* LOAD_METHOD, for class methods */
assert(cframe.use_tracing == 0);
SpecializedCacheEntry *caches = GET_CACHE();
_PyAttrCache *cache1 = &caches[-1].attr;
_PyObjectCache *cache2 = &caches[-2].obj;

PyObject *cls = TOP();
DEOPT_IF(!PyType_Check(cls), LOAD_METHOD);
DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != cache1->tp_version,
LOAD_METHOD);
assert(cache1->tp_version != 0);

STAT_INC(LOAD_METHOD, hit);
PyObject *res = cache2->obj;
assert(res != NULL);
Py_INCREF(res);
LOAD_CLASS_ATTR_OR_METHOD(METHOD);
SET_TOP(NULL);
Py_DECREF(cls);
PUSH(res);
Expand Down
18 changes: 9 additions & 9 deletions Python/opcode_targets.h

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

32 changes: 25 additions & 7 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@

#include <stdlib.h> // rand()

// Forward declarations
static int specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name, _PyAttrCache *cache1, _PyObjectCache *cache2, int oparg,
int oparg_class);

/* For guidance on adding or extending families of instructions see
* ./adaptive.md
*/
Expand Down Expand Up @@ -243,7 +248,7 @@ static uint8_t adaptive_opcodes[256] = {

/* The number of cache entries required for a "family" of instructions. */
static uint8_t cache_requirements[256] = {
[LOAD_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */
[LOAD_ATTR] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache*/
[LOAD_GLOBAL] = 2, /* _PyAdaptiveEntry and _PyLoadGlobalCache */
[LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */
[BINARY_ADD] = 0,
Expand Down Expand Up @@ -693,8 +698,11 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
{
_PyAdaptiveEntry *cache0 = &cache->adaptive;
_PyAttrCache *cache1 = &cache[-1].attr;
_PyObjectCache *cache2 = &cache[-2].obj;

int err;
if (PyModule_CheckExact(owner)) {
int err = specialize_module_load_attr(owner, instr, name, cache0, cache1,
err = specialize_module_load_attr(owner, instr, name, cache0, cache1,
LOAD_ATTR, LOAD_ATTR_MODULE);
if (err) {
goto fail;
Expand All @@ -707,6 +715,14 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
return -1;
}
}
if (PyType_Check(owner)) {
err = specialize_class_load_method(owner, instr, name, cache1, cache2,
LOAD_ATTR, LOAD_ATTR_CLASS);
if (err) {
goto fail;
}
goto success;
}
PyObject *descr;
DesciptorClassification kind = analyze_descriptor(type, name, &descr, 0);
switch(kind) {
Expand Down Expand Up @@ -764,7 +780,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, Sp
case ABSENT:
break;
}
int err = specialize_dict_access(
err = specialize_dict_access(
owner, instr, type, kind, name, cache0, cache1,
LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT
);
Expand Down Expand Up @@ -907,7 +923,8 @@ load_method_fail_kind(DesciptorClassification kind)

static int
specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
_PyAttrCache *cache1, _PyObjectCache *cache2)
_PyAttrCache *cache1, _PyObjectCache *cache2, int oparg,
int oparg_class)
{

PyObject *descr = NULL;
Expand All @@ -918,10 +935,10 @@ specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr, PyObject *nam
case NON_DESCRIPTOR:
cache1->tp_version = ((PyTypeObject *)owner)->tp_version_tag;
cache2->obj = descr;
*instr = _Py_MAKECODEUNIT(LOAD_METHOD_CLASS, _Py_OPARG(*instr));
*instr = _Py_MAKECODEUNIT(oparg_class, _Py_OPARG(*instr));
return 0;
default:
SPECIALIZATION_FAIL(LOAD_METHOD, load_method_fail_kind(kind));
SPECIALIZATION_FAIL(oparg, load_method_fail_kind(kind));
return -1;
}
}
Expand Down Expand Up @@ -951,7 +968,8 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
}
}
if (PyType_Check(owner)) {
int err = specialize_class_load_method(owner, instr, name, cache1, cache2);
int err = specialize_class_load_method(owner, instr, name, cache1, cache2,
LOAD_METHOD, LOAD_METHOD_CLASS);
if (err) {
goto fail;
}
Expand Down