Skip to content

Commit

Permalink
GH-91095: Specialize calls to normal Python classes. (GH-99331)
Browse files Browse the repository at this point in the history
  • Loading branch information
markshannon committed Jun 22, 2023
1 parent c01da28 commit 04492cb
Show file tree
Hide file tree
Showing 20 changed files with 511 additions and 189 deletions.
1 change: 1 addition & 0 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ struct _specialization_cache {
// *args nor **kwargs (as required by BINARY_SUBSCR_GETITEM):
PyObject *getitem;
uint32_t getitem_version;
PyObject *init;
};

/* The *real* layout of a type object when allocated on the heap */
Expand Down
24 changes: 24 additions & 0 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,30 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l
return new_frame;
}

/* Pushes a trampoline frame without checking for space.
* Must be guarded by _PyThreadState_HasStackSpace() */
static inline _PyInterpreterFrame *
_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, int prev_instr)
{
CALL_STAT_INC(frames_pushed);
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top;
tstate->datastack_top += code->co_framesize;
assert(tstate->datastack_top < tstate->datastack_limit);
frame->f_funcobj = Py_None;
frame->f_executable = Py_NewRef(code);
#ifdef Py_DEBUG
frame->f_builtins = NULL;
frame->f_globals = NULL;
#endif
frame->f_locals = NULL;
frame->stacktop = code->co_nlocalsplus + stackdepth;
frame->frame_obj = NULL;
frame->prev_instr = _PyCode_CODE(code) + prev_instr;
frame->owner = FRAME_OWNED_BY_THREAD;
frame->return_offset = 0;
return frame;
}

static inline
PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
{
Expand Down
2 changes: 2 additions & 0 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,10 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
}

extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
PyObject *_PyType_NewManagedObject(PyTypeObject *type);

extern int _PyObject_InitializeDict(PyObject *obj);
int _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp);
extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name, PyObject *value);
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
Expand Down
46 changes: 23 additions & 23 deletions Include/internal/pycore_opcode.h

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

108 changes: 55 additions & 53 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_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
"CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
"CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
"CALL_NO_KW_ALLOC_AND_ENTER_INIT",
],
}

Expand Down
1 change: 1 addition & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def pseudo_op(name, op, real_ops):
def_op('UNARY_NOT', 12)

def_op('UNARY_INVERT', 15)
def_op('EXIT_INIT_CHECK', 16)

# We reserve 17 as it is the initial value for the specializing counter
# This helps us catch cases where we attempt to execute a cache.
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ def delx(self): del self.__x
'10P' # PySequenceMethods
'2P' # PyBufferProcs
'6P'
'1PI' # Specializer cache
'1PIP' # Specializer cache
)
class newstyleclass(object): pass
# Separate block for PyDictKeysObject with 8 keys and 5 entries
Expand Down
24 changes: 23 additions & 1 deletion Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -1614,8 +1614,30 @@ def func():

self.run_and_compare(func, EXPECTED_EVENTS)

def test_settrace_error(self):
def test_correct_tracing_quickened_call_class_init(self):

class C:
def __init__(self):
self

def func():
C()

EXPECTED_EVENTS = [
(0, 'call'),
(1, 'line'),
(-3, 'call'),
(-2, 'line'),
(-2, 'return'),
(1, 'return')]

self.run_and_compare(func, EXPECTED_EVENTS)
# Quicken
for _ in range(100):
func()
self.run_and_compare(func, EXPECTED_EVENTS)

def test_settrace_error(self):
raised = False
def error_once(frame, event, arg):
nonlocal raised
Expand Down
Loading

0 comments on commit 04492cb

Please sign in to comment.