mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Pull Request resolved: https://github.com/pytorch/pytorch/pull/145603 Approved by: https://github.com/jansel, https://github.com/anijain2305
93 lines
2.7 KiB
C++
93 lines
2.7 KiB
C++
#pragma once
|
|
|
|
#include <torch/csrc/utils/python_compat.h>
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
#include <torch/csrc/dynamo/utils.h>
|
|
#include <torch/csrc/utils/pybind.h>
|
|
|
|
extern "C" {
|
|
|
|
#if IS_PYTHON_3_11_PLUS
|
|
using FrameLocalsFrameType = _PyInterpreterFrame;
|
|
#else
|
|
using FrameLocalsFrameType = PyFrameObject;
|
|
#endif // IS_PYTHON_3_11_PLUS
|
|
|
|
/**
|
|
* Utility to view a frame's localsplus (locals + cells + freevars)
|
|
* in C/C++ and Python, without changing the state of the frame.
|
|
*
|
|
* Notes on usage:
|
|
* - C/C++ can directly read the frame's localsplus using an index.
|
|
* - Cell/free variables are unboxed.
|
|
* - Can be converted into a dict for use in Python.
|
|
* The dict is constructed once per FrameLocalsMapping, lazily.
|
|
* - Lifetime should not exceed the lifetime of the frame
|
|
*
|
|
* How do guards use FrameLocalsMapping?
|
|
* - When a guard accesses a frame's localsplus, we find the index of the
|
|
* variable name in the frame's code object and create a
|
|
* FrameLocalsGuardAccessor.
|
|
* - We create a FrameLocalsMapping for the frame that we pass on to guard eval.
|
|
* - LeafGuards/GuardManagers/GuardAccessors now need to define how they
|
|
* handle FrameLocalsMapping. By default, the FrameLocalsMapping is converted
|
|
* to a Python dict and the guard check is performed on the resulting dict.
|
|
* - Some guard checks don't actually depend on the input arguments, e.g. they
|
|
* only check global state. In this case, no dict conversion of
|
|
* FrameLocalsMapping is done.
|
|
* - FrameLocalsGuardAccessor is like DictGetItemGuardAccessor, except it knows
|
|
* how to handle FrameLocalsMapping - by using the framelocals variable name
|
|
* index that it was given when it was built.
|
|
*/
|
|
typedef struct VISIBILITY_HIDDEN FrameLocalsMapping {
|
|
private:
|
|
py::object _code_obj;
|
|
// can't use localsplus directly due to closure variables:
|
|
// - in 3.11+, the closure vars in the frame's closure object and
|
|
// the corresponding localsplus entry is nullptr
|
|
// - regardless of Python version, we need to unbox the cell variable
|
|
std::vector<py::handle> _framelocals;
|
|
|
|
py::object _dict{py::none()};
|
|
|
|
void _realize_dict();
|
|
|
|
public:
|
|
explicit FrameLocalsMapping(FrameLocalsFrameType* frame);
|
|
|
|
PyObject* get(int idx);
|
|
|
|
bool dict_realized() const {
|
|
return _dict.is_none();
|
|
}
|
|
|
|
// Borrowed reference
|
|
PyDictObject* to_dict() {
|
|
if (this->dict_realized()) {
|
|
_realize_dict();
|
|
}
|
|
return (PyDictObject*)_dict.ptr();
|
|
}
|
|
} FrameLocalsMapping;
|
|
|
|
#else
|
|
|
|
// opaque type for C
|
|
typedef struct FrameLocalsMapping FrameLocalsMapping;
|
|
|
|
#endif
|
|
|
|
// Borrowed reference
|
|
PyDictObject* framelocals_mapping_to_dict(FrameLocalsMapping* map);
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
|
|
py::tuple code_framelocals_names(py::handle code);
|
|
#endif
|