Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-40521: Disable method cache in subinterpreters #19960

Merged
merged 1 commit into from
May 6, 2020
Merged
Changes from all 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
22 changes: 19 additions & 3 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class object "PyObject *" "&PyBaseObject_Type"

#include "clinic/typeobject.c.h"

/* bpo-40521: Type method cache is shared by all subinterpreters */
#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
# define MCACHE
#endif

#ifdef MCACHE
/* Support type attribute cache */

/* The cache can keep references to the names alive for longer than
Expand Down Expand Up @@ -47,6 +53,7 @@ struct method_cache_entry {

static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
static unsigned int next_version_tag = 0;
#endif

#define MCACHE_STATS 0

Expand Down Expand Up @@ -216,6 +223,7 @@ _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_d
unsigned int
PyType_ClearCache(void)
{
#ifdef MCACHE
Py_ssize_t i;
unsigned int cur_version_tag = next_version_tag - 1;

Expand All @@ -240,6 +248,9 @@ PyType_ClearCache(void)
/* mark all version tags as invalid */
PyType_Modified(&PyBaseObject_Type);
return cur_version_tag;
#else
return 0;
#endif
}

void
Expand Down Expand Up @@ -350,6 +361,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
Py_TPFLAGS_VALID_VERSION_TAG);
}

#ifdef MCACHE
static int
assign_version_tag(PyTypeObject *type)
{
Expand Down Expand Up @@ -396,6 +408,7 @@ assign_version_tag(PyTypeObject *type)
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
return 1;
}
#endif


static PyMemberDef type_members[] = {
Expand Down Expand Up @@ -3232,12 +3245,12 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
{
PyObject *res;
int error;
unsigned int h;

#ifdef MCACHE
if (MCACHE_CACHEABLE_NAME(name) &&
_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) {
/* fast path */
h = MCACHE_HASH_METHOD(type, name);
unsigned int h = MCACHE_HASH_METHOD(type, name);
if (method_cache[h].version == type->tp_version_tag &&
method_cache[h].name == name) {
#if MCACHE_STATS
Expand All @@ -3246,6 +3259,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
return method_cache[h].value;
}
}
#endif

/* We may end up clearing live exceptions below, so make sure it's ours. */
assert(!PyErr_Occurred());
Expand All @@ -3267,8 +3281,9 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
return NULL;
}

#ifdef MCACHE
if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) {
h = MCACHE_HASH_METHOD(type, name);
unsigned int h = MCACHE_HASH_METHOD(type, name);
method_cache[h].version = type->tp_version_tag;
method_cache[h].value = res; /* borrowed */
Py_INCREF(name);
Expand All @@ -3281,6 +3296,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
#endif
Py_SETREF(method_cache[h].name, name);
}
#endif
return res;
}

Expand Down