Skip to content

Commit a51742a

Browse files
gh-93911: Specialize LOAD_ATTR_PROPERTY (GH-93912)
1 parent 0ff626f commit a51742a

File tree

12 files changed

+172
-71
lines changed

12 files changed

+172
-71
lines changed

Include/internal/pycore_descrobject.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef Py_INTERNAL_DESCROBJECT_H
2+
#define Py_INTERNAL_DESCROBJECT_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
typedef struct {
12+
PyObject_HEAD
13+
PyObject *prop_get;
14+
PyObject *prop_set;
15+
PyObject *prop_del;
16+
PyObject *prop_doc;
17+
PyObject *prop_name;
18+
int getter_doc;
19+
} propertyobject;
20+
21+
typedef propertyobject _PyPropertyObject;
22+
23+
#ifdef __cplusplus
24+
}
25+
#endif
26+
#endif /* !Py_INTERNAL_DESCROBJECT_H */

Include/internal/pycore_opcode.h

Lines changed: 14 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode.h

Lines changed: 27 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ def jabs_op(name, op):
287287
"LOAD_ATTR_CLASS",
288288
"LOAD_ATTR_INSTANCE_VALUE",
289289
"LOAD_ATTR_MODULE",
290+
"LOAD_ATTR_PROPERTY",
290291
"LOAD_ATTR_SLOT",
291292
"LOAD_ATTR_WITH_HINT",
292293
# These will always push [unbound method, self] onto the stack.

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,7 @@ PYTHON_HEADERS= \
15951595
$(srcdir)/Include/internal/pycore_condvar.h \
15961596
$(srcdir)/Include/internal/pycore_context.h \
15971597
$(srcdir)/Include/internal/pycore_dict.h \
1598+
$(srcdir)/Include/internal/pycore_descrobject.h \
15981599
$(srcdir)/Include/internal/pycore_dtoa.h \
15991600
$(srcdir)/Include/internal/pycore_exceptions.h \
16001601
$(srcdir)/Include/internal/pycore_fileutils.h \
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Specialize ``LOAD_ATTR`` for ``property()`` attributes.

Objects/descrobject.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "pycore_pystate.h" // _PyThreadState_GET()
77
#include "pycore_tuple.h" // _PyTuple_ITEMS()
88
#include "structmember.h" // PyMemberDef
9+
#include "pycore_descrobject.h"
910

1011
/*[clinic input]
1112
class mappingproxy "mappingproxyobject *" "&PyDictProxy_Type"
@@ -1501,16 +1502,6 @@ class property(object):
15011502
15021503
*/
15031504

1504-
typedef struct {
1505-
PyObject_HEAD
1506-
PyObject *prop_get;
1507-
PyObject *prop_set;
1508-
PyObject *prop_del;
1509-
PyObject *prop_doc;
1510-
PyObject *prop_name;
1511-
int getter_doc;
1512-
} propertyobject;
1513-
15141505
static PyObject * property_copy(PyObject *, PyObject *, PyObject *,
15151506
PyObject *);
15161507

PCbuild/pythoncore.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
<ClInclude Include="..\Include\internal\pycore_compile.h" />
208208
<ClInclude Include="..\Include\internal\pycore_condvar.h" />
209209
<ClInclude Include="..\Include\internal\pycore_context.h" />
210+
<ClInclude Include="..\Include\internal\pycore_descrobject.h" />
210211
<ClInclude Include="..\Include\internal\pycore_dtoa.h" />
211212
<ClInclude Include="..\Include\internal\pycore_exceptions.h" />
212213
<ClInclude Include="..\Include\internal\pycore_fileutils.h" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@
528528
<ClInclude Include="..\Include\internal\pycore_context.h">
529529
<Filter>Include\internal</Filter>
530530
</ClInclude>
531+
<ClInclude Include="..\Include\internal\pycore_descrobject.h">
532+
<Filter>Include\internal</Filter>
533+
</ClInclude>
531534
<ClInclude Include="..\Include\internal\pycore_dtoa.h">
532535
<Filter>Include\internal</Filter>
533536
</ClInclude>

Python/ceval.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3626,7 +3626,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
36263626
}
36273627

36283628
TARGET(LOAD_ATTR_CLASS) {
3629-
/* LOAD_METHOD, for class methods */
36303629
assert(cframe.use_tracing == 0);
36313630
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
36323631

@@ -3649,6 +3648,46 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
36493648
NOTRACE_DISPATCH();
36503649
}
36513650

3651+
TARGET(LOAD_ATTR_PROPERTY) {
3652+
assert(cframe.use_tracing == 0);
3653+
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
3654+
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
3655+
3656+
PyObject *owner = TOP();
3657+
PyTypeObject *cls = Py_TYPE(owner);
3658+
uint32_t type_version = read_u32(cache->type_version);
3659+
DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
3660+
assert(type_version != 0);
3661+
PyObject *fget = read_obj(cache->descr);
3662+
PyFunctionObject *f = (PyFunctionObject *)fget;
3663+
uint32_t func_version = read_u32(cache->keys_version);
3664+
assert(func_version != 0);
3665+
DEOPT_IF(f->func_version != func_version, LOAD_ATTR);
3666+
PyCodeObject *code = (PyCodeObject *)f->func_code;
3667+
assert(code->co_argcount == 1);
3668+
STAT_INC(LOAD_ATTR, hit);
3669+
3670+
Py_INCREF(fget);
3671+
_PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, f);
3672+
if (new_frame == NULL) {
3673+
goto error;
3674+
}
3675+
SET_TOP(NULL);
3676+
int push_null = !(oparg & 1);
3677+
STACK_SHRINK(push_null);
3678+
new_frame->localsplus[0] = owner;
3679+
for (int i = 1; i < code->co_nlocalsplus; i++) {
3680+
new_frame->localsplus[i] = NULL;
3681+
}
3682+
_PyFrame_SetStackPointer(frame, stack_pointer);
3683+
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
3684+
frame->prev_instr = next_instr - 1;
3685+
new_frame->previous = frame;
3686+
frame = cframe.current_frame = new_frame;
3687+
CALL_STAT_INC(inlined_py_calls);
3688+
goto start_frame;
3689+
}
3690+
36523691
TARGET(STORE_ATTR_ADAPTIVE) {
36533692
assert(cframe.use_tracing == 0);
36543693
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
@@ -4548,7 +4587,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
45484587
}
45494588

45504589
TARGET(LOAD_ATTR_METHOD_WITH_VALUES) {
4551-
/* LOAD_METHOD, with cached method object */
4590+
/* Cached method object */
45524591
assert(cframe.use_tracing == 0);
45534592
PyObject *self = TOP();
45544593
PyTypeObject *self_cls = Py_TYPE(self);
@@ -4574,8 +4613,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
45744613
}
45754614

45764615
TARGET(LOAD_ATTR_METHOD_WITH_DICT) {
4577-
/* LOAD_METHOD, with a dict
4578-
Can be either a managed dict, or a tp_dictoffset offset.*/
4616+
/* Can be either a managed dict, or a tp_dictoffset offset.*/
45794617
assert(cframe.use_tracing == 0);
45804618
PyObject *self = TOP();
45814619
PyTypeObject *self_cls = Py_TYPE(self);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy