Skip to content

Commit f47d48d

Browse files
committed
[lldb] Support the Python stable C API in PythonString::AsUTF8
This conditionally reimplements PythonString::AsUTF8 using PyUnicode_AsUTF8String instead of PyUnicode_AsUTF8AndSize. The latter is slightly more efficient because it caches the result, which also means we can return a StringRef instead of having to allocate a std::string. We pick the most efficient one depending on whether or not we're targeting the Python 3.10 stable API, however we now always return the result as a std::string.
1 parent dbaa82b commit f47d48d

File tree

4 files changed

+38
-26
lines changed

4 files changed

+38
-26
lines changed

lldb/bindings/python/python-wrapper.swig

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallTypeScript(
173173
else
174174
result = pfunc(value_arg, dict, SWIGBridge::ToSWIGWrapper(*options_sp));
175175

176-
retval = result.Str().GetString().str();
176+
retval = result.Str().GetString();
177177

178178
return true;
179179
}
@@ -604,7 +604,7 @@ lldb_private::python::SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedComma
604604
if (result.IsNone())
605605
return std::nullopt;
606606

607-
return result.Str().GetString().str();
607+
return result.Str().GetString();
608608
}
609609

610610
StructuredData::DictionarySP
@@ -807,7 +807,7 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordProcess(
807807

808808
auto result = pfunc(SWIGBridge::ToSWIGWrapper(process), dict);
809809

810-
output = result.Str().GetString().str();
810+
output = result.Str().GetString();
811811

812812
return true;
813813
}
@@ -831,7 +831,7 @@ std::optional<std::string> lldb_private::python::SWIGBridge::LLDBSWIGPythonRunSc
831831

832832
auto result = pfunc(SWIGBridge::ToSWIGWrapper(std::move(thread)), dict);
833833

834-
return result.Str().GetString().str();
834+
return result.Str().GetString();
835835
}
836836

837837
bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordTarget(
@@ -854,7 +854,7 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordTarget(
854854

855855
auto result = pfunc(SWIGBridge::ToSWIGWrapper(target), dict);
856856

857-
output = result.Str().GetString().str();
857+
output = result.Str().GetString();
858858

859859
return true;
860860
}
@@ -878,7 +878,7 @@ std::optional<std::string> lldb_private::python::SWIGBridge::LLDBSWIGPythonRunSc
878878

879879
auto result = pfunc(SWIGBridge::ToSWIGWrapper(std::move(frame)), dict);
880880

881-
return result.Str().GetString().str();
881+
return result.Str().GetString();
882882
}
883883

884884
bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue(
@@ -901,7 +901,7 @@ bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue(
901901

902902
auto result = pfunc(SWIGBridge::ToSWIGWrapper(value), dict);
903903

904-
output = result.Str().GetString().str();
904+
output = result.Str().GetString();
905905

906906
return true;
907907
}

lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -405,28 +405,40 @@ bool PythonString::Check(PyObject *py_obj) {
405405
return false;
406406
}
407407

408-
llvm::StringRef PythonString::GetString() const {
408+
std::string PythonString::GetString() const {
409409
auto s = AsUTF8();
410410
if (!s) {
411411
llvm::consumeError(s.takeError());
412-
return llvm::StringRef("");
412+
return "";
413413
}
414414
return s.get();
415415
}
416416

417-
Expected<llvm::StringRef> PythonString::AsUTF8() const {
417+
Expected<std::string> PythonString::AsUTF8() const {
418418
if (!IsValid())
419419
return nullDeref();
420420

421-
Py_ssize_t size;
422-
const char *data;
421+
// PyUnicode_AsUTF8AndSize caches the UTF-8 representation of the string in
422+
// the Unicode object, making it more efficient than PyUnicode_AsUTF8String.
423+
#if defined(Py_LIMITED_API) && (Py_LIMITED_API < 0x030a0000)
424+
PyObject *py_bytes = PyUnicode_AsUTF8String(m_py_obj);
425+
if (!py_bytes)
426+
return exception();
423427

424-
data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
428+
auto release_py_str =
429+
llvm::make_scope_exit([py_bytes] { Py_DECREF(py_bytes); });
425430

426-
if (!data)
431+
Py_ssize_t size = PyBytes_Size(py_bytes);
432+
const char *str = PyBytes_AsString(py_bytes);
433+
#else
434+
Py_ssize_t size;
435+
const char *str = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
436+
#endif
437+
438+
if (!str)
427439
return exception();
428440

429-
return llvm::StringRef(data, size);
441+
return std::string(str, size);
430442
}
431443

432444
size_t PythonString::GetSize() const {
@@ -1248,12 +1260,12 @@ class TextPythonFile : public PythonIOFile {
12481260
// EOF
12491261
return Status();
12501262
}
1251-
auto stringref = pystring.get().AsUTF8();
1252-
if (!stringref)
1263+
auto str = pystring.get().AsUTF8();
1264+
if (!str)
12531265
// Cloning since the wrapped exception may still reference the PyThread.
1254-
return Status::FromError(stringref.takeError()).Clone();
1255-
num_bytes = stringref.get().size();
1256-
memcpy(buf, stringref.get().begin(), num_bytes);
1266+
return Status::FromError(str.takeError()).Clone();
1267+
num_bytes = str->size();
1268+
memcpy(buf, str->c_str(), num_bytes);
12571269
return Status();
12581270
}
12591271
};

lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,9 @@ class PythonString : public TypedPythonObject<PythonString> {
460460

461461
static bool Check(PyObject *py_obj);
462462

463-
llvm::StringRef GetString() const; // safe, empty string on error
463+
std::string GetString() const; // safe, empty string on error
464464

465-
llvm::Expected<llvm::StringRef> AsUTF8() const;
465+
llvm::Expected<std::string> AsUTF8() const;
466466

467467
size_t GetSize() const;
468468

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2715,8 +2715,8 @@ bool ScriptInterpreterPythonImpl::GetShortHelpForCommandObject(
27152715

27162716
if (py_return.IsAllocated() && PythonString::Check(py_return.get())) {
27172717
PythonString py_string(PyRefType::Borrowed, py_return.get());
2718-
llvm::StringRef return_data(py_string.GetString());
2719-
dest.assign(return_data.data(), return_data.size());
2718+
std::string return_data = py_string.GetString();
2719+
dest.assign(return_data.c_str(), return_data.size());
27202720
return true;
27212721
}
27222722

@@ -2996,8 +2996,8 @@ bool ScriptInterpreterPythonImpl::GetLongHelpForCommandObject(
29962996
bool got_string = false;
29972997
if (py_return.IsAllocated() && PythonString::Check(py_return.get())) {
29982998
PythonString str(PyRefType::Borrowed, py_return.get());
2999-
llvm::StringRef str_data(str.GetString());
3000-
dest.assign(str_data.data(), str_data.size());
2999+
std::string str_data = str.GetString();
3000+
dest.assign(str_data.c_str(), str_data.size());
30013001
got_string = true;
30023002
}
30033003

0 commit comments

Comments
 (0)