Skip to content

Commit 263cd22

Browse files
committed
__frozendict__ hack
1 parent a7f6000 commit 263cd22

File tree

5 files changed

+63
-4
lines changed

5 files changed

+63
-4
lines changed

Include/internal/pycore_object.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,8 +863,7 @@ static inline Py_hash_t
863863
_PyObject_HashFast(PyObject *op)
864864
{
865865
if (PyUnicode_CheckExact(op)) {
866-
Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(
867-
_PyASCIIObject_CAST(op)->hash);
866+
Py_hash_t hash = PyUnstable_Unicode_GET_CACHED_HASH(op);
868867
if (hash != -1) {
869868
return hash;
870869
}

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ def exec_module(self, module):
761761
raise ImportError(f'cannot load module {module.__name__!r} when '
762762
'get_code() returns None')
763763
_bootstrap._call_with_frames_removed(exec, code, module.__dict__)
764+
if module.__dict__.get('__frozendict__', False):
765+
module.frozendict()
764766

765767
def load_module(self, fullname):
766768
"""This method is deprecated."""

Objects/dictobject.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6925,6 +6925,11 @@ _PyObject_MaterializeManagedDict(PyObject *obj)
69256925
int
69266926
_PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
69276927
{
6928+
if (!PyDict_Check(dict)) {
6929+
PyErr_BadInternalCall();
6930+
return -1;
6931+
}
6932+
69286933
if (value == NULL) {
69296934
Py_hash_t hash = _PyObject_HashFast(name);
69306935
if (hash == -1) {

Objects/moduleobject.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,9 +1266,27 @@ module_dir(PyObject *self, PyObject *args)
12661266
return result;
12671267
}
12681268

1269+
1270+
static PyObject *
1271+
module_frozendict(PyObject *self, PyObject *Py_UNUSED(args))
1272+
{
1273+
PyModuleObject *mod = _PyModule_CAST(self);
1274+
1275+
PyObject *frozendict;
1276+
frozendict = PyObject_CallOneArg((PyObject*)&PyFrozenDict_Type, mod->md_dict);
1277+
if (frozendict == NULL) {
1278+
return NULL;
1279+
}
1280+
1281+
Py_SETREF(mod->md_dict, frozendict);
1282+
1283+
Py_RETURN_NONE;
1284+
}
1285+
12691286
static PyMethodDef module_methods[] = {
12701287
{"__dir__", module_dir, METH_NOARGS,
12711288
PyDoc_STR("__dir__() -> list\nspecialized dir() implementation")},
1289+
{"frozendict", module_frozendict, METH_NOARGS, NULL},
12721290
{0}
12731291
};
12741292

Objects/typeobject.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3988,7 +3988,7 @@ subtype_dict(PyObject *obj, void *context)
39883988
int
39893989
_PyObject_SetDict(PyObject *obj, PyObject *value)
39903990
{
3991-
if (value != NULL && !PyDict_Check(value)) {
3991+
if (value != NULL && !_PyAnyDict_Check(value)) {
39923992
PyErr_Format(PyExc_TypeError,
39933993
"__dict__ must be set to a dictionary, "
39943994
"not a '%.200s'", Py_TYPE(value)->tp_name);
@@ -4891,6 +4891,37 @@ type_new_init(type_new_ctx *ctx)
48914891
}
48924892

48934893

4894+
static int
4895+
type_new_frozendict(PyTypeObject *type)
4896+
{
4897+
PyObject *__frozendict__;
4898+
if (PyDict_GetItemStringRef(type->tp_dict, "__frozendict__",
4899+
&__frozendict__) < 0) {
4900+
return -1;
4901+
}
4902+
if (__frozendict__ == NULL) {
4903+
return 0;
4904+
}
4905+
int is_true = PyObject_IsTrue(__frozendict__);
4906+
Py_DECREF(__frozendict__);
4907+
if (is_true < 0) {
4908+
return -1;
4909+
}
4910+
if (!is_true) {
4911+
return 0;
4912+
}
4913+
4914+
PyObject *frozendict;
4915+
frozendict = PyObject_CallOneArg((PyObject*)&PyFrozenDict_Type, type->tp_dict);
4916+
if (frozendict == NULL) {
4917+
return -1;
4918+
}
4919+
4920+
Py_SETREF(type->tp_dict, frozendict);
4921+
return 0;
4922+
}
4923+
4924+
48944925
static PyObject*
48954926
type_new_impl(type_new_ctx *ctx)
48964927
{
@@ -4930,6 +4961,10 @@ type_new_impl(type_new_ctx *ctx)
49304961
goto error;
49314962
}
49324963

4964+
if (type_new_frozendict(type) < 0) {
4965+
goto error;
4966+
}
4967+
49334968
assert(_PyType_CheckConsistency(type));
49344969
#if defined(Py_GIL_DISABLED) && defined(Py_DEBUG) && SIZEOF_VOID_P > 4
49354970
// After this point, other threads can potentally use this type.
@@ -5977,7 +6012,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
59776012
for (Py_ssize_t i = 0; i < n; i++) {
59786013
PyObject *base = PyTuple_GET_ITEM(mro, i);
59796014
PyObject *dict = lookup_tp_dict(_PyType_CAST(base));
5980-
assert(dict && PyDict_Check(dict));
6015+
assert(dict && _PyAnyDict_Check(dict));
59816016
if (_PyDict_GetItemRef_KnownHash((PyDictObject *)dict, name, hash, &res) < 0) {
59826017
*error = -1;
59836018
goto done;

0 commit comments

Comments
 (0)