Skip to content

gh-123660: Internal macros for accessing empty string/bytes singletons #123643

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
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
6 changes: 5 additions & 1 deletion Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -797,11 +797,15 @@ struct _Py_global_strings {
? (PyObject*)&_Py_SINGLETON(strings).ascii[(CH)] \
: (PyObject*)&_Py_SINGLETON(strings).latin1[(CH) - 128])

#define _Py_EMPTY_STRING ((PyObject *)(&_Py_STR(empty)))

#define _Py_EMPTY_BYTES ((PyObject *)&_Py_SINGLETON(bytes_empty))

/* _Py_DECLARE_STR() should precede all uses of _Py_STR() in a function.

This is true even if the same string has already been declared
elsewhere, even in the same file. Mismatched duplicates are detected
by Tools/scripts/generate-global-objects.py.
by Tools/build/generate_global_objects.py.

Pairing _Py_DECLARE_STR() with every use of _Py_STR() makes sure the
string keeps working even if the declaration is removed somewhere
Expand Down
5 changes: 2 additions & 3 deletions Include/internal/pycore_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ struct _parser_runtime_state {
struct _expr dummy_name;
};

_Py_DECLARE_STR(empty, "")
#if defined(Py_DEBUG) && defined(Py_GIL_DISABLED)
#define _parser_runtime_state_INIT \
{ \
.mutex = {0}, \
.dummy_name = { \
.kind = Name_kind, \
.v.Name.id = &_Py_STR(empty), \
.v.Name.id = _Py_EMPTY_STRING, \
.v.Name.ctx = Load, \
.lineno = 1, \
.col_offset = 0, \
Expand All @@ -50,7 +49,7 @@ _Py_DECLARE_STR(empty, "")
{ \
.dummy_name = { \
.kind = Name_kind, \
.v.Name.id = &_Py_STR(empty), \
.v.Name.id = _Py_EMPTY_STRING, \
.v.Name.ctx = Load, \
.lineno = 1, \
.col_offset = 0, \
Expand Down
2 changes: 1 addition & 1 deletion InternalDocs/string_interning.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ They are collected from CPython sources using `make regen-global-objects`
(`Tools/build/generate_global_objects.py`), which generates code
for declaration, initialization and finalization.

The empty string is one of the singletons: `_Py_STR(empty)`.
The empty string is one of the singletons: `_Py_EMPTY_STRING`.

The three sets of singletons (`_Py_LATIN1_CHR`, `_Py_ID`, `_Py_STR`)
are disjoint.
Expand Down
4 changes: 2 additions & 2 deletions Modules/_io/bufferedio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ _buffered_readline(buffered *self, Py_ssize_t limit)
Py_CLEAR(res);
goto end;
}
Py_XSETREF(res, PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks));
Py_XSETREF(res, PyBytes_Join(_Py_EMPTY_BYTES, chunks));

end:
LEAVE_BUFFERED(self)
Expand Down Expand Up @@ -1736,7 +1736,7 @@ _bufferedreader_read_all(buffered *self)
goto cleanup;
}
else {
tmp = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
tmp = PyBytes_Join(_Py_EMPTY_BYTES, chunks);
res = tmp;
goto cleanup;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_io/iobase.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ _io__RawIOBase_readall_impl(PyObject *self)
return NULL;
}
}
result = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
result = PyBytes_Join(_Py_EMPTY_BYTES, chunks);
Py_DECREF(chunks);
return result;
}
Expand Down
7 changes: 3 additions & 4 deletions Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2059,8 +2059,7 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
if (chunks != NULL) {
if (result != NULL && PyList_Append(chunks, result) < 0)
goto fail;
_Py_DECLARE_STR(empty, "");
Py_XSETREF(result, PyUnicode_Join(&_Py_STR(empty), chunks));
Py_XSETREF(result, PyUnicode_Join(_Py_EMPTY_STRING, chunks));
if (result == NULL)
goto fail;
Py_CLEAR(chunks);
Expand Down Expand Up @@ -2322,13 +2321,13 @@ _textiowrapper_readline(textio *self, Py_ssize_t limit)
goto error;
Py_DECREF(line);
}
line = PyUnicode_Join(&_Py_STR(empty), chunks);
line = PyUnicode_Join(_Py_EMPTY_STRING, chunks);
if (line == NULL)
goto error;
Py_CLEAR(chunks);
}
if (line == NULL) {
line = &_Py_STR(empty);
line = _Py_EMPTY_STRING;
}

return line;
Expand Down
4 changes: 2 additions & 2 deletions Modules/_sre/sre.c
Original file line number Diff line number Diff line change
Expand Up @@ -2914,11 +2914,11 @@ expand_template(TemplateObject *self, MatchObject *match)
}

if (PyUnicode_Check(self->literal)) {
result = _PyUnicode_JoinArray(&_Py_STR(empty), out, count);
result = _PyUnicode_JoinArray(_Py_EMPTY_STRING, out, count);
}
else {
Py_SET_SIZE(list, count);
result = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), list);
result = PyBytes_Join(_Py_EMPTY_BYTES, list);
}

cleanup:
Expand Down
2 changes: 1 addition & 1 deletion Objects/bytesobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer,
#define CHARACTERS _Py_SINGLETON(bytes_characters)
#define CHARACTER(ch) \
((PyBytesObject *)&(CHARACTERS[ch]));
#define EMPTY (&_Py_SINGLETON(bytes_empty))
#define EMPTY ((PyBytesObject *)_Py_EMPTY_BYTES)


// Return a reference to the immortal empty bytes string singleton.
Expand Down
5 changes: 2 additions & 3 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,6 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
goto failed;
}

#define emptystring (PyObject *)&_Py_SINGLETON(bytes_empty)
struct _PyCodeConstructor con = {
.filename = filename_ob,
.name = funcname_ob,
Expand All @@ -918,8 +917,8 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
.consts = nulltuple,
.names = nulltuple,
.localsplusnames = nulltuple,
.localspluskinds = emptystring,
.exceptiontable = emptystring,
.localspluskinds = _Py_EMPTY_BYTES,
.exceptiontable = _Py_EMPTY_BYTES,
.stacksize = 1,
};
result = _PyCode_New(&con);
Expand Down
15 changes: 8 additions & 7 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
/* Function object implementation */

#include "Python.h"
#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
#include "pycore_global_strings.h" // _Py_EMPTY_STRING
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_Occurred()


static const char *
Expand Down Expand Up @@ -1036,8 +1037,8 @@ func_clear(PyFunctionObject *op)
// However, name and qualname could be str subclasses, so they
// could have reference cycles. The solution is to replace them
// with a genuinely immutable string.
Py_SETREF(op->func_name, &_Py_STR(empty));
Py_SETREF(op->func_qualname, &_Py_STR(empty));
Py_SETREF(op->func_name, _Py_EMPTY_STRING);
Py_SETREF(op->func_qualname, _Py_EMPTY_STRING);
return 0;
}

Expand Down
6 changes: 3 additions & 3 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ static int unicode_is_singleton(PyObject *unicode);
static inline PyObject* unicode_get_empty(void)
{
_Py_DECLARE_STR(empty, "");
return &_Py_STR(empty);
return _Py_EMPTY_STRING;
}

/* This dictionary holds per-interpreter interned strings.
Expand Down Expand Up @@ -340,7 +340,7 @@ init_global_interned_strings(PyInterpreterState *interp)
assert(s == LATIN1(i));
}
#ifdef Py_DEBUG
assert(_PyUnicode_CheckConsistency(&_Py_STR(empty), 1));
assert(_PyUnicode_CheckConsistency(_Py_EMPTY_STRING, 1));

for (int i = 0; i < 256; i++) {
assert(_PyUnicode_CheckConsistency(LATIN1(i), 1));
Expand Down Expand Up @@ -1720,7 +1720,7 @@ unicode_dealloc(PyObject *unicode)
static int
unicode_is_singleton(PyObject *unicode)
{
if (unicode == &_Py_STR(empty)) {
if (unicode == _Py_EMPTY_STRING) {
return 1;
}

Expand Down
4 changes: 2 additions & 2 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ dummy_func(
PyObject *value_o = PyStackRef_AsPyObjectBorrow(value);
EXIT_IF(!PyUnicode_CheckExact(value_o));
STAT_INC(TO_BOOL, hit);
if (value_o == &_Py_STR(empty)) {
if (value_o == _Py_EMPTY_STRING) {
assert(_Py_IsImmortalLoose(value_o));
res = PyStackRef_False;
}
Expand Down Expand Up @@ -1682,7 +1682,7 @@ dummy_func(
DECREF_INPUTS();
ERROR_IF(true, error);
}
PyObject *str_o = _PyUnicode_JoinArray(&_Py_STR(empty), pieces_o, oparg);
PyObject *str_o = _PyUnicode_JoinArray(_Py_EMPTY_STRING, pieces_o, oparg);
STACKREFS_TO_PYOBJECTS_CLEANUP(pieces_o);
DECREF_INPUTS();
ERROR_IF(str_o == NULL, error);
Expand Down
9 changes: 3 additions & 6 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3040,8 +3040,7 @@ codegen_from_import(struct compiler *c, stmt_ty s)
ADDOP_NAME(c, LOC(s), IMPORT_NAME, s->v.ImportFrom.module, names);
}
else {
_Py_DECLARE_STR(empty, "");
ADDOP_NAME(c, LOC(s), IMPORT_NAME, &_Py_STR(empty), names);
ADDOP_NAME(c, LOC(s), IMPORT_NAME, _Py_EMPTY_STRING, names);
}
for (Py_ssize_t i = 0; i < n; i++) {
alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i);
Expand Down Expand Up @@ -4115,8 +4114,7 @@ codegen_joined_str(struct compiler *c, expr_ty e)
location loc = LOC(e);
Py_ssize_t value_count = asdl_seq_LEN(e->v.JoinedStr.values);
if (value_count > STACK_USE_GUIDELINE) {
_Py_DECLARE_STR(empty, "");
ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty)));
ADDOP_LOAD_CONST_NEW(c, loc, _Py_EMPTY_STRING);
ADDOP_NAME(c, loc, LOAD_METHOD, &_Py_ID(join), names);
ADDOP_I(c, loc, BUILD_LIST, 0);
for (Py_ssize_t i = 0; i < asdl_seq_LEN(e->v.JoinedStr.values); i++) {
Expand All @@ -4131,8 +4129,7 @@ codegen_joined_str(struct compiler *c, expr_ty e)
ADDOP_I(c, loc, BUILD_STRING, value_count);
}
else if (value_count == 0) {
_Py_DECLARE_STR(empty, "");
ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty)));
ADDOP_LOAD_CONST_NEW(c, loc, _Py_EMPTY_STRING);
}
}
return SUCCESS;
Expand Down
2 changes: 1 addition & 1 deletion Python/crossinterp.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ _convert_exc_to_TracebackException(PyObject *exc, PyObject **p_tbexc)

// We accommodate backports here.
#ifndef _Py_EMPTY_STR
# define _Py_EMPTY_STR &_Py_STR(empty)
# define _Py_EMPTY_STR _Py_EMPTY_STRING
#endif

static const char *
Expand Down
4 changes: 2 additions & 2 deletions Python/executor_cases.c.h

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

4 changes: 2 additions & 2 deletions Python/generated_cases.c.h

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

2 changes: 1 addition & 1 deletion Python/optimizer_symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ _Py_uop_sym_truthiness(_Py_UopsSymbol *sym)
return !_PyLong_IsZero((PyLongObject *)value);
}
if (tp == &PyUnicode_Type) {
return value != &_Py_STR(empty);
return value != _Py_EMPTY_STRING;
}
if (tp == &PyBool_Type) {
return value == Py_True;
Expand Down
4 changes: 2 additions & 2 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -2741,10 +2741,10 @@ const struct _PyCode8 _Py_InitCleanup = {
_PyVarObject_HEAD_INIT(&PyCode_Type, 3),
.co_consts = (PyObject *)&_Py_SINGLETON(tuple_empty),
.co_names = (PyObject *)&_Py_SINGLETON(tuple_empty),
.co_exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty),
.co_exceptiontable = _Py_EMPTY_BYTES,
.co_flags = CO_OPTIMIZED | CO_NO_MONITORING_EVENTS,
.co_localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty),
.co_localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty),
.co_localspluskinds = _Py_EMPTY_BYTES,
.co_filename = &_Py_ID(__init__),
.co_name = &_Py_ID(__init__),
.co_qualname = &_Py_ID(__init__),
Expand Down
Loading