extern PyObject* _PyEval_GetBuiltins(PyThreadState *tstate);
-extern PyObject* _PyEval_BuiltinsFromGlobals(
- PyThreadState *tstate,
- PyObject *globals);
// Trampoline API
PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *);
PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *);
+// Loads the __builtins__ object from the globals dict. Returns a new reference.
+extern PyObject *_PyDict_LoadBuiltinsFromGlobals(PyObject *globals);
+
/* Consumes references to key and value */
PyAPI_FUNC(int) _PyDict_SetItem_Take2(PyDictObject *op, PyObject *key, PyObject *value);
extern int _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value);
#ifndef Py_GIL_DISABLED
# define _Py_INCREF_DICT Py_INCREF
# define _Py_DECREF_DICT Py_DECREF
+# define _Py_INCREF_BUILTINS Py_INCREF
+# define _Py_DECREF_BUILTINS Py_DECREF
#else
static inline Py_ssize_t
_PyDict_UniqueId(PyDictObject *mp)
Py_ssize_t id = _PyDict_UniqueId((PyDictObject *)op);
_Py_THREAD_DECREF_OBJECT(op, id);
}
+
+// Like `_Py_INCREF_DICT`, but also handles non-dict objects because builtins
+// may not be a dict.
+static inline void
+_Py_INCREF_BUILTINS(PyObject *op)
+{
+ if (PyDict_CheckExact(op)) {
+ _Py_INCREF_DICT(op);
+ }
+ else {
+ Py_INCREF(op);
+ }
+}
+
+static inline void
+_Py_DECREF_BUILTINS(PyObject *op)
+{
+ if (PyDict_CheckExact(op)) {
+ _Py_DECREF_DICT(op);
+ }
+ else {
+ Py_DECREF(op);
+ }
+}
#endif
#ifdef __cplusplus
assert(ix >= 0 || PyStackRef_IsNull(*res));
}
+PyObject *
+_PyDict_LoadBuiltinsFromGlobals(PyObject *globals)
+{
+ if (!PyDict_Check(globals)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ PyDictObject *mp = (PyDictObject *)globals;
+ PyObject *key = &_Py_ID(__builtins__);
+ Py_hash_t hash = unicode_get_hash(key);
+
+ // Use the stackref variant to avoid reference count contention on the
+ // builtins module in the free threading build. It's important not to
+ // make any escaping calls between the lookup and the `PyStackRef_CLOSE()`
+ // because the `ref` is not visible to the GC.
+ _PyStackRef ref;
+ Py_ssize_t ix = _Py_dict_lookup_threadsafe_stackref(mp, key, hash, &ref);
+ if (ix == DKIX_ERROR) {
+ return NULL;
+ }
+ if (PyStackRef_IsNull(ref)) {
+ return Py_NewRef(PyEval_GetBuiltins());
+ }
+ PyObject *builtins = PyStackRef_AsPyObjectBorrow(ref);
+ if (PyModule_Check(builtins)) {
+ builtins = _PyModule_GetDict(builtins);
+ assert(builtins != NULL);
+ }
+ _Py_INCREF_BUILTINS(builtins);
+ PyStackRef_CLOSE(ref);
+ return builtins;
+}
+
/* Consumes references to key and value */
static int
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
/* Frame object implementation */
#include "Python.h"
-#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
+#include "pycore_ceval.h" // _PyEval_SetOpcodeTrace()
#include "pycore_code.h" // CO_FAST_LOCAL, etc.
+#include "pycore_dict.h" // _PyDict_LoadBuiltinsFromGlobals()
#include "pycore_function.h" // _PyFunction_FromConstructor()
#include "pycore_moduleobject.h" // _PyModule_GetDict()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
- PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
+ PyObject *builtins = _PyDict_LoadBuiltinsFromGlobals(globals);
if (builtins == NULL) {
return NULL;
}
.fc_closure = NULL
};
PyFunctionObject *func = _PyFunction_FromConstructor(&desc);
+ _Py_DECREF_BUILTINS(builtins);
if (func == NULL) {
return NULL;
}
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame->f_frame);
return Py_NewRef(gen);
}
-
-PyObject*
-_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
-{
- PyObject *builtins = PyDict_GetItemWithError(globals, &_Py_ID(__builtins__));
- if (builtins) {
- if (PyModule_Check(builtins)) {
- builtins = _PyModule_GetDict(builtins);
- assert(builtins != NULL);
- }
- return builtins;
- }
- if (PyErr_Occurred()) {
- return NULL;
- }
-
- return _PyEval_GetBuiltins(tstate);
-}
/* Function object implementation */
#include "Python.h"
-#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
#include "pycore_dict.h" // _Py_INCREF_DICT()
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
}
_Py_INCREF_DICT(constr->fc_globals);
op->func_globals = constr->fc_globals;
- if (PyDict_Check(constr->fc_builtins)) {
- _Py_INCREF_DICT(constr->fc_builtins);
- }
- else {
- Py_INCREF(constr->fc_builtins);
- }
+ _Py_INCREF_BUILTINS(constr->fc_builtins);
op->func_builtins = constr->fc_builtins;
op->func_name = Py_NewRef(constr->fc_name);
op->func_qualname = Py_NewRef(constr->fc_qualname);
assert(PyDict_Check(globals));
_Py_INCREF_DICT(globals);
- PyThreadState *tstate = _PyThreadState_GET();
-
PyCodeObject *code_obj = (PyCodeObject *)code;
_Py_INCREF_CODE(code_obj);
goto error;
}
- builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
+ builtins = _PyDict_LoadBuiltinsFromGlobals(globals);
if (builtins == NULL) {
goto error;
}
- if (PyDict_Check(builtins)) {
- _Py_INCREF_DICT(builtins);
- }
- else {
- Py_INCREF(builtins);
- }
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL) {
PyObject *builtins = op->func_builtins;
op->func_builtins = NULL;
if (builtins != NULL) {
- if (PyDict_Check(builtins)) {
- _Py_DECREF_DICT(builtins);
- }
- else {
- Py_DECREF(builtins);
- }
+ _Py_DECREF_BUILTINS(builtins);
}
Py_CLEAR(op->func_module);
Py_CLEAR(op->func_defaults);
if (locals == NULL) {
locals = globals;
}
- PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
+ PyObject *builtins = _PyDict_LoadBuiltinsFromGlobals(globals);
if (builtins == NULL) {
return NULL;
}
.fc_closure = NULL
};
PyFunctionObject *func = _PyFunction_FromConstructor(&desc);
+ _Py_DECREF_BUILTINS(builtins);
if (func == NULL) {
return NULL;
}
if (defaults == NULL) {
return NULL;
}
- PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
+ PyObject *builtins = _PyDict_LoadBuiltinsFromGlobals(globals);
if (builtins == NULL) {
Py_DECREF(defaults);
return NULL;
Py_XDECREF(func);
Py_XDECREF(kwnames);
PyMem_Free(newargs);
+ _Py_DECREF_BUILTINS(builtins);
Py_DECREF(defaults);
return res;
}