xref: /aosp_15_r20/external/pytorch/c10/core/impl/PyObjectSlot.cpp (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
1 #include <c10/core/impl/PyObjectSlot.h>
2 
3 namespace c10::impl {
4 
PyObjectSlot()5 PyObjectSlot::PyObjectSlot() : pyobj_interpreter_(nullptr), pyobj_(nullptr) {}
6 
~PyObjectSlot()7 PyObjectSlot::~PyObjectSlot() {
8   maybe_destroy_pyobj();
9 }
10 
maybe_destroy_pyobj()11 void PyObjectSlot::maybe_destroy_pyobj() {
12   if (owns_pyobj()) {
13     TORCH_INTERNAL_ASSERT(pyobj_interpreter_ != nullptr);
14     TORCH_INTERNAL_ASSERT(pyobj_ != nullptr);
15     (*pyobj_interpreter_.load(std::memory_order_acquire))
16         ->decref(_unchecked_untagged_pyobj(), /*has_pyobj_slot*/ true);
17     // NB: this destructor can only be entered when there are no
18     // references to this C++ object (obviously), NOR any references
19     // to the PyObject (if there are references to the PyObject,
20     // then the PyObject holds an owning reference to the tensor).
21     // So it is OK to clear pyobj_ here as it is impossible for it to
22     // be used again (modulo weak reference races)
23     pyobj_ = nullptr; // for safety
24   }
25 }
26 
pyobj_interpreter()27 PyInterpreter* PyObjectSlot::pyobj_interpreter() {
28   return pyobj_interpreter_.load(std::memory_order_acquire);
29 }
30 
_unchecked_untagged_pyobj() const31 PyObject* PyObjectSlot::_unchecked_untagged_pyobj() const {
32   // NOLINTNEXTLINE(performance-no-int-to-ptr)
33   return reinterpret_cast<PyObject*>(
34       reinterpret_cast<uintptr_t>(pyobj_) & ~0x1ULL);
35 }
36 
unchecked_clear_pyobj(PyInterpreter * interpreter)37 void PyObjectSlot::unchecked_clear_pyobj(PyInterpreter* interpreter) {
38   TORCH_INTERNAL_ASSERT_DEBUG_ONLY(interpreter == pyobj_interpreter_.load());
39   pyobj_ = nullptr;
40 }
41 
load_pyobj_interpreter() const42 PyInterpreter& PyObjectSlot::load_pyobj_interpreter() const {
43   auto interpreter = pyobj_interpreter_.load(std::memory_order_acquire);
44   if (interpreter) {
45     return *interpreter;
46   }
47   TORCH_CHECK(
48       false,
49       "cannot access PyObject for Tensor on interpreter ",
50       (*pyobj_interpreter_.load())->name());
51 }
52 
check_interpreter(PyInterpreter * interpreter)53 bool PyObjectSlot::check_interpreter(PyInterpreter* interpreter) {
54   return interpreter == pyobj_interpreter();
55 }
56 
has_pyobj_nonhermetic()57 bool PyObjectSlot::has_pyobj_nonhermetic() {
58   return check_pyobj(pyobj_interpreter(), /*ignore_hermetic_tls=*/true)
59       .has_value();
60 }
61 
owns_pyobj()62 bool PyObjectSlot::owns_pyobj() {
63   // NOLINTNEXTLINE(performance-no-int-to-ptr)
64   return reinterpret_cast<uintptr_t>(pyobj_) & 1;
65 }
66 
set_owns_pyobj(bool b)67 void PyObjectSlot::set_owns_pyobj(bool b) {
68   // NOLINTNEXTLINE(performance-no-int-to-ptr)
69   pyobj_ = reinterpret_cast<PyObject*>(
70       reinterpret_cast<uintptr_t>(_unchecked_untagged_pyobj()) | b);
71 }
72 
73 } // namespace c10::impl
74