1 #include <c10/core/impl/PyObjectSlot.h> 2 3 namespace c10::impl { 4 PyObjectSlot()5PyObjectSlot::PyObjectSlot() : pyobj_interpreter_(nullptr), pyobj_(nullptr) {} 6 ~PyObjectSlot()7PyObjectSlot::~PyObjectSlot() { 8 maybe_destroy_pyobj(); 9 } 10 maybe_destroy_pyobj()11void 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()27PyInterpreter* PyObjectSlot::pyobj_interpreter() { 28 return pyobj_interpreter_.load(std::memory_order_acquire); 29 } 30 _unchecked_untagged_pyobj() const31PyObject* 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)37void PyObjectSlot::unchecked_clear_pyobj(PyInterpreter* interpreter) { 38 TORCH_INTERNAL_ASSERT_DEBUG_ONLY(interpreter == pyobj_interpreter_.load()); 39 pyobj_ = nullptr; 40 } 41 load_pyobj_interpreter() const42PyInterpreter& 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)53bool PyObjectSlot::check_interpreter(PyInterpreter* interpreter) { 54 return interpreter == pyobj_interpreter(); 55 } 56 has_pyobj_nonhermetic()57bool PyObjectSlot::has_pyobj_nonhermetic() { 58 return check_pyobj(pyobj_interpreter(), /*ignore_hermetic_tls=*/true) 59 .has_value(); 60 } 61 owns_pyobj()62bool 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)67void 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