PyAPI_FUNC(void) _PyObjectArray_Free(PyObject **array, PyObject **scratch);
PyAPI_FUNC(PyObject *) _PyEval_GetANext(PyObject *aiter);
-PyAPI_FUNC(PyObject *) _PyEval_LoadGlobal(PyObject *globals, PyObject *builtins, PyObject *name);
+PyAPI_FUNC(void) _PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name, _PyStackRef *writeto);
PyAPI_FUNC(PyObject *) _PyEval_GetAwaitable(PyObject *iterable, int oparg);
PyAPI_FUNC(PyObject *) _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name);
#include "pycore_object.h" // PyManagedDictPointer
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE
+#include "pycore_stackref.h" // _PyStackRef
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key);
*/
extern Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
extern Py_ssize_t _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
+extern Py_ssize_t _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr);
extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *);
extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key);
PyAPI_FUNC(PyObject *)_PyDict_LoadGlobal(PyDictObject *, PyDictObject *, PyObject *);
+PyAPI_FUNC(void) _PyDict_LoadGlobalStackRef(PyDictObject *, PyDictObject *, PyObject *, _PyStackRef *);
/* Consumes references to key and value */
PyAPI_FUNC(int) _PyDict_SetItem_Take2(PyDictObject *op, PyObject *key, PyObject *value);
return ix;
}
+Py_ssize_t
+_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
+{
+ PyDictKeysObject *dk = _Py_atomic_load_ptr(&mp->ma_keys);
+ if (dk->dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact(key)) {
+ Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
+ if (ix == DKIX_EMPTY) {
+ *value_addr = PyStackRef_NULL;
+ return ix;
+ }
+ else if (ix >= 0) {
+ PyObject **addr_of_value = &DK_UNICODE_ENTRIES(dk)[ix].me_value;
+ PyObject *value = _Py_atomic_load_ptr(addr_of_value);
+ if (value == NULL) {
+ *value_addr = PyStackRef_NULL;
+ return DKIX_EMPTY;
+ }
+ if (_Py_IsImmortal(value) || _PyObject_HasDeferredRefcount(value)) {
+ *value_addr = (_PyStackRef){ .bits = (uintptr_t)value | Py_TAG_DEFERRED };
+ return ix;
+ }
+ if (_Py_TryIncrefCompare(addr_of_value, value)) {
+ *value_addr = PyStackRef_FromPyObjectSteal(value);
+ return ix;
+ }
+ }
+ }
+
+ PyObject *obj;
+ Py_ssize_t ix = _Py_dict_lookup_threadsafe(mp, key, hash, &obj);
+ if (ix >= 0 && obj != NULL) {
+ *value_addr = PyStackRef_FromPyObjectSteal(obj);
+ }
+ else {
+ *value_addr = PyStackRef_NULL;
+ }
+ return ix;
+}
+
#else // Py_GIL_DISABLED
Py_ssize_t
return ix;
}
+Py_ssize_t
+_Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr)
+{
+ PyObject *val;
+ Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &val);
+ *value_addr = val == NULL ? PyStackRef_NULL : PyStackRef_FromPyObjectNew(val);
+ return ix;
+}
+
#endif
int
return value;
}
+void
+_PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, PyObject *key, _PyStackRef *res)
+{
+ Py_ssize_t ix;
+ Py_hash_t hash;
+
+ hash = _PyObject_HashFast(key);
+ if (hash == -1) {
+ *res = PyStackRef_NULL;
+ return;
+ }
+
+ /* namespace 1: globals */
+ ix = _Py_dict_lookup_threadsafe_stackref(globals, key, hash, res);
+ if (ix == DKIX_ERROR) {
+ *res = PyStackRef_NULL;
+ }
+ if (ix != DKIX_EMPTY && !PyStackRef_IsNull(*res)) {
+ return;
+ }
+
+ /* namespace 2: builtins */
+ ix = _Py_dict_lookup_threadsafe_stackref(builtins, key, hash, res);
+ assert(ix >= 0 || PyStackRef_IsNull(*res));
+}
+
/* Consumes references to key and value */
static int
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
&& PyDict_CheckExact(BUILTINS()))
{
v_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
- (PyDictObject *)BUILTINS(),
- name);
+ (PyDictObject *)BUILTINS(),
+ name);
if (v_o == NULL) {
if (!_PyErr_Occurred(tstate)) {
/* _PyDict_LoadGlobal() returns NULL without raising
#endif /* ENABLE_SPECIALIZATION */
}
- op(_LOAD_GLOBAL, ( -- res, null if (oparg & 1))) {
+ // res[1] because we need a pointer to res to pass it to _PyEval_LoadGlobalStackRef
+ op(_LOAD_GLOBAL, ( -- res[1], null if (oparg & 1))) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
- PyObject *res_o = _PyEval_LoadGlobal(GLOBALS(), BUILTINS(), name);
- ERROR_IF(res_o == NULL, error);
+ _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res);
+ ERROR_IF(PyStackRef_IsNull(*res), error);
null = PyStackRef_NULL;
- res = PyStackRef_FromPyObjectSteal(res_o);
}
macro(LOAD_GLOBAL) =
return awaitable;
}
-PyObject *
-_PyEval_LoadGlobal(PyObject *globals, PyObject *builtins, PyObject *name)
+void
+_PyEval_LoadGlobalStackRef(PyObject *globals, PyObject *builtins, PyObject *name, _PyStackRef *writeto)
{
- PyObject *res;
if (PyDict_CheckExact(globals) && PyDict_CheckExact(builtins)) {
- res = _PyDict_LoadGlobal((PyDictObject *)globals,
+ _PyDict_LoadGlobalStackRef((PyDictObject *)globals,
(PyDictObject *)builtins,
- name);
- if (res == NULL && !PyErr_Occurred()) {
+ name, writeto);
+ if (PyStackRef_IsNull(*writeto) && !PyErr_Occurred()) {
/* _PyDict_LoadGlobal() returns NULL without raising
* an exception if the key doesn't exist */
_PyEval_FormatExcCheckArg(PyThreadState_GET(), PyExc_NameError,
else {
/* Slow-path if globals or builtins is not a dict */
/* namespace 1: globals */
+ PyObject *res;
if (PyMapping_GetOptionalItem(globals, name, &res) < 0) {
- return NULL;
+ *writeto = PyStackRef_NULL;
+ return;
}
if (res == NULL) {
/* namespace 2: builtins */
if (PyMapping_GetOptionalItem(builtins, name, &res) < 0) {
- return NULL;
+ *writeto = PyStackRef_NULL;
+ return;
}
if (res == NULL) {
_PyEval_FormatExcCheckArg(
NAME_ERROR_MSG, name);
}
}
+ *writeto = PyStackRef_FromPyObjectSteal(res);
}
- return res;
}
PyObject *
}
case _LOAD_GLOBAL: {
- _PyStackRef res;
+ _PyStackRef *res;
_PyStackRef null = PyStackRef_NULL;
oparg = CURRENT_OPARG();
+ res = &stack_pointer[0];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
- PyObject *res_o = _PyEval_LoadGlobal(GLOBALS(), BUILTINS(), name);
- if (res_o == NULL) JUMP_TO_ERROR();
+ _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res);
+ if (PyStackRef_IsNull(*res)) JUMP_TO_ERROR();
null = PyStackRef_NULL;
- res = PyStackRef_FromPyObjectSteal(res_o);
- stack_pointer[0] = res;
if (oparg & 1) stack_pointer[1] = null;
stack_pointer += 1 + (oparg & 1);
assert(WITHIN_STACK_BOUNDS());
PREDICTED(LOAD_GLOBAL);
_Py_CODEUNIT *this_instr = next_instr - 5;
(void)this_instr;
- _PyStackRef res;
+ _PyStackRef *res;
_PyStackRef null = PyStackRef_NULL;
// _SPECIALIZE_LOAD_GLOBAL
{
/* Skip 1 cache entry */
// _LOAD_GLOBAL
{
+ res = &stack_pointer[0];
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
- PyObject *res_o = _PyEval_LoadGlobal(GLOBALS(), BUILTINS(), name);
- if (res_o == NULL) goto error;
+ _PyEval_LoadGlobalStackRef(GLOBALS(), BUILTINS(), name, res);
+ if (PyStackRef_IsNull(*res)) goto error;
null = PyStackRef_NULL;
- res = PyStackRef_FromPyObjectSteal(res_o);
}
- stack_pointer[0] = res;
if (oparg & 1) stack_pointer[1] = null;
stack_pointer += 1 + (oparg & 1);
assert(WITHIN_STACK_BOUNDS());
}
case _LOAD_GLOBAL: {
- _Py_UopsSymbol *res;
+ _Py_UopsSymbol **res;
_Py_UopsSymbol *null = NULL;
- res = sym_new_not_null(ctx);
+ res = &stack_pointer[0];
+ for (int _i = 1; --_i >= 0;) {
+ res[_i] = sym_new_not_null(ctx);
+ }
null = sym_new_null(ctx);
- stack_pointer[0] = res;
if (oparg & 1) stack_pointer[1] = null;
stack_pointer += 1 + (oparg & 1);
assert(WITHIN_STACK_BOUNDS());