Skip to content

Commit 04492cb

Browse files
authored
GH-91095: Specialize calls to normal Python classes. (GH-99331)
1 parent c01da28 commit 04492cb

20 files changed

+511
-189
lines changed

Include/cpython/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ struct _specialization_cache {
246246
// *args nor **kwargs (as required by BINARY_SUBSCR_GETITEM):
247247
PyObject *getitem;
248248
uint32_t getitem_version;
249+
PyObject *init;
249250
};
250251

251252
/* The *real* layout of a type object when allocated on the heap */

Include/internal/pycore_frame.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,30 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l
272272
return new_frame;
273273
}
274274

275+
/* Pushes a trampoline frame without checking for space.
276+
* Must be guarded by _PyThreadState_HasStackSpace() */
277+
static inline _PyInterpreterFrame *
278+
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, int prev_instr)
279+
{
280+
CALL_STAT_INC(frames_pushed);
281+
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top;
282+
tstate->datastack_top += code->co_framesize;
283+
assert(tstate->datastack_top < tstate->datastack_limit);
284+
frame->f_funcobj = Py_None;
285+
frame->f_executable = Py_NewRef(code);
286+
#ifdef Py_DEBUG
287+
frame->f_builtins = NULL;
288+
frame->f_globals = NULL;
289+
#endif
290+
frame->f_locals = NULL;
291+
frame->stacktop = code->co_nlocalsplus + stackdepth;
292+
frame->frame_obj = NULL;
293+
frame->prev_instr = _PyCode_CODE(code) + prev_instr;
294+
frame->owner = FRAME_OWNED_BY_THREAD;
295+
frame->return_offset = 0;
296+
return frame;
297+
}
298+
275299
static inline
276300
PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
277301
{

Include/internal/pycore_object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,10 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
355355
}
356356

357357
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
358+
PyObject *_PyType_NewManagedObject(PyTypeObject *type);
358359

359360
extern int _PyObject_InitializeDict(PyObject *obj);
361+
int _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp);
360362
extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
361363
PyObject *name, PyObject *value);
362364
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,

Include/internal/pycore_opcode.h

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

Include/opcode.h

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

Lib/_opcode_metadata.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
8686
"CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
8787
"CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
88+
"CALL_NO_KW_ALLOC_AND_ENTER_INIT",
8889
],
8990
}
9091

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def pseudo_op(name, op, real_ops):
9797
def_op('UNARY_NOT', 12)
9898

9999
def_op('UNARY_INVERT', 15)
100+
def_op('EXIT_INIT_CHECK', 16)
100101

101102
# We reserve 17 as it is the initial value for the specializing counter
102103
# This helps us catch cases where we attempt to execute a cache.

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1557,7 +1557,7 @@ def delx(self): del self.__x
15571557
'10P' # PySequenceMethods
15581558
'2P' # PyBufferProcs
15591559
'6P'
1560-
'1PI' # Specializer cache
1560+
'1PIP' # Specializer cache
15611561
)
15621562
class newstyleclass(object): pass
15631563
# Separate block for PyDictKeysObject with 8 keys and 5 entries

Lib/test/test_sys_settrace.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1614,8 +1614,30 @@ def func():
16141614

16151615
self.run_and_compare(func, EXPECTED_EVENTS)
16161616

1617-
def test_settrace_error(self):
1617+
def test_correct_tracing_quickened_call_class_init(self):
1618+
1619+
class C:
1620+
def __init__(self):
1621+
self
1622+
1623+
def func():
1624+
C()
16181625

1626+
EXPECTED_EVENTS = [
1627+
(0, 'call'),
1628+
(1, 'line'),
1629+
(-3, 'call'),
1630+
(-2, 'line'),
1631+
(-2, 'return'),
1632+
(1, 'return')]
1633+
1634+
self.run_and_compare(func, EXPECTED_EVENTS)
1635+
# Quicken
1636+
for _ in range(100):
1637+
func()
1638+
self.run_and_compare(func, EXPECTED_EVENTS)
1639+
1640+
def test_settrace_error(self):
16191641
raised = False
16201642
def error_once(frame, event, arg):
16211643
nonlocal raised

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