|
9 | 9 | #endif |
10 | 10 |
|
11 | 11 | #include "cinderx/Common/ref.h" |
12 | | -#include "cinderx/Common/util.h" |
13 | 12 | #include "cinderx/Jit/debug_info.h" |
14 | | -#include "cinderx/Jit/frame_header.h" |
15 | 13 | #include "cinderx/Jit/threaded_compile.h" |
16 | 14 |
|
17 | 15 | #include <deque> |
18 | | -#include <unordered_map> |
| 16 | +#include <limits> |
| 17 | +#include <unordered_set> |
19 | 18 |
|
20 | 19 | namespace jit { |
21 | 20 |
|
| 21 | +constexpr ptrdiff_t kInvalidYieldFromOffset = |
| 22 | + std::numeric_limits<ptrdiff_t>::max(); |
| 23 | + |
| 24 | +// Information about how a specific yield instruction should resume. |
22 | 25 | class GenYieldPoint { |
23 | 26 | public: |
24 | | - explicit GenYieldPoint( |
25 | | - std::size_t deopt_idx, |
26 | | - bool is_yield_from, |
27 | | - ptrdiff_t yield_from_offs) |
28 | | - : deopt_idx_(deopt_idx), |
29 | | - isYieldFrom_(is_yield_from), |
30 | | - yieldFromOffs_(yield_from_offs) {} |
31 | | - |
32 | | - void setResumeTarget(uint64_t resume_target) { |
33 | | - resume_target_ = resume_target; |
34 | | - } |
35 | | - |
36 | | - uint64_t resumeTarget() const { |
37 | | - return resume_target_; |
38 | | - } |
39 | | - |
40 | | - std::size_t deoptIdx() const { |
41 | | - return deopt_idx_; |
| 27 | + static constexpr int resumeTargetOffset() { |
| 28 | + return offsetof(GenYieldPoint, resume_target_); |
42 | 29 | } |
43 | 30 |
|
44 | | - bool isYieldFrom() const { |
45 | | - return isYieldFrom_; |
46 | | - } |
| 31 | + GenYieldPoint(std::size_t deopt_idx, ptrdiff_t yield_from_offset); |
47 | 32 |
|
48 | | - ptrdiff_t yieldFromOffset() const { |
49 | | - return yieldFromOffs_; |
50 | | - } |
| 33 | + // Get and set what address the yield should resume from. |
| 34 | + uintptr_t resumeTarget() const; |
| 35 | + void setResumeTarget(uintptr_t resume_target); |
51 | 36 |
|
52 | | - static constexpr int resumeTargetOffset() { |
53 | | - return offsetof(GenYieldPoint, resume_target_); |
54 | | - } |
| 37 | + std::size_t deoptIdx() const; |
| 38 | + bool isYieldFrom() const; |
| 39 | + ptrdiff_t yieldFromOffset() const; |
55 | 40 |
|
56 | 41 | private: |
57 | | - uint64_t resume_target_{0}; |
| 42 | + uintptr_t resume_target_{0}; |
58 | 43 | const std::size_t deopt_idx_; |
59 | | - const bool isYieldFrom_; |
60 | | - const ptrdiff_t yieldFromOffs_; |
| 44 | + const ptrdiff_t yield_from_offset_; |
61 | 45 | }; |
62 | 46 |
|
63 | 47 | class alignas(16) RuntimeFrameState { |
64 | 48 | public: |
| 49 | + static constexpr int64_t codeOffset() { |
| 50 | + return offsetof(RuntimeFrameState, code_); |
| 51 | + } |
| 52 | + |
65 | 53 | RuntimeFrameState( |
66 | 54 | BorrowedRef<PyCodeObject> code, |
67 | | - BorrowedRef<> builtins, |
68 | | - BorrowedRef<> globals, |
| 55 | + BorrowedRef<PyDictObject> builtins, |
| 56 | + BorrowedRef<PyDictObject> globals, |
69 | 57 | BorrowedRef<PyFunctionObject> func = nullptr) |
70 | | - : code_(code), builtins_(builtins), globals_(globals), func_(func) {} |
| 58 | + : code_{code}, builtins_{builtins}, globals_{globals}, func_{func} {} |
71 | 59 |
|
72 | | - bool isGen() const { |
73 | | - return code()->co_flags & kCoFlagsAnyGenerator; |
74 | | - } |
75 | | - |
76 | | - BorrowedRef<PyCodeObject> code() const { |
77 | | - return code_; |
78 | | - } |
79 | | - |
80 | | - BorrowedRef<> builtins() const { |
81 | | - return builtins_; |
82 | | - } |
83 | | - |
84 | | - BorrowedRef<> globals() const { |
85 | | - return globals_; |
86 | | - } |
| 60 | + // Check if this is a generator frame. |
| 61 | + bool isGen() const; |
87 | 62 |
|
88 | | - BorrowedRef<PyFunctionObject> func() const { |
89 | | - return func_; |
90 | | - } |
91 | | - |
92 | | - static constexpr int64_t codeOffset() { |
93 | | - return offsetof(RuntimeFrameState, code_); |
94 | | - } |
| 63 | + BorrowedRef<PyCodeObject> code() const; |
| 64 | + BorrowedRef<PyDictObject> builtins() const; |
| 65 | + BorrowedRef<PyDictObject> globals() const; |
| 66 | + BorrowedRef<PyFunctionObject> func() const; |
95 | 67 |
|
96 | 68 | private: |
97 | | - // These are owned by the CodeRuntime that owns this RuntimeFrameState. |
| 69 | + // All fields are owned by the CodeRuntime that owns this RuntimeFrameState. |
| 70 | + |
98 | 71 | BorrowedRef<PyCodeObject> code_; |
99 | | - BorrowedRef<> builtins_; |
100 | | - BorrowedRef<> globals_; |
| 72 | + BorrowedRef<PyDictObject> builtins_; |
| 73 | + BorrowedRef<PyDictObject> globals_; |
| 74 | + // The function is only set for inlined frames. |
101 | 75 | BorrowedRef<PyFunctionObject> func_; |
102 | 76 | }; |
103 | 77 |
|
104 | 78 | // Runtime data for a PyCodeObject object, containing caches and any other data |
105 | 79 | // associated with a JIT-compiled function. |
106 | 80 | class alignas(16) CodeRuntime { |
107 | 81 | public: |
108 | | - CodeRuntime( |
109 | | - PyCodeObject* code, |
110 | | - PyObject* builtins, |
111 | | - PyObject* globals, |
112 | | - PyFunctionObject* func = nullptr) |
113 | | - : frame_state_(code, builtins, globals, func) { |
114 | | - // TASK(T88040922): Until we work out something smarter, force code, |
115 | | - // globals, and builtins objects for compiled functions to live as long as |
116 | | - // the JIT is initialized. |
117 | | - addReference(BorrowedRef(code)); |
118 | | - addReference(builtins); |
119 | | - addReference(globals); |
120 | | - if (func != nullptr) { |
121 | | - addReference(&func->ob_base); |
122 | | - } |
| 82 | + static constexpr int64_t frameStateOffset() { |
| 83 | +#pragma GCC diagnostic push |
| 84 | +#pragma GCC diagnostic ignored "-Winvalid-offsetof" |
| 85 | + return offsetof(CodeRuntime, frame_state_); |
| 86 | +#pragma GCC diagnostic pop |
123 | 87 | } |
124 | 88 |
|
125 | | - explicit CodeRuntime(PyFunctionObject* func) |
126 | | - : CodeRuntime( |
127 | | - reinterpret_cast<PyCodeObject*>(func->func_code), |
128 | | - func->func_builtins, |
129 | | - func->func_globals) {} |
| 89 | + static constexpr int64_t codeOffset() { |
| 90 | + return CodeRuntime::frameStateOffset() + RuntimeFrameState::codeOffset(); |
| 91 | + } |
| 92 | + |
| 93 | + explicit CodeRuntime(BorrowedRef<PyFunctionObject> func); |
| 94 | + CodeRuntime( |
| 95 | + BorrowedRef<PyCodeObject> code, |
| 96 | + BorrowedRef<PyDictObject> builtins, |
| 97 | + BorrowedRef<PyDictObject> globals); |
130 | 98 |
|
131 | 99 | template <typename... Args> |
132 | 100 | RuntimeFrameState* allocateRuntimeFrameState(Args&&... args) { |
133 | | - // Serialize as we modify the globally shared runtimes data. |
134 | | - ThreadedCompileSerialize guard; |
135 | | - inlined_frame_states_.emplace_back( |
136 | | - std::make_unique<RuntimeFrameState>(std::forward<Args>(args)...)); |
137 | | - return inlined_frame_states_.back().get(); |
138 | | - } |
139 | | - |
140 | | - const RuntimeFrameState* frameState() const { |
141 | | - return &frame_state_; |
| 101 | + return inlined_frame_states_ |
| 102 | + .emplace_back( |
| 103 | + std::make_unique<RuntimeFrameState>(std::forward<Args>(args)...)) |
| 104 | + .get(); |
142 | 105 | } |
143 | 106 |
|
144 | | - // Release any references this CodeRuntime holds to Python objects. |
145 | | - void releaseReferences(); |
146 | | - |
147 | | - // Ensure that this CodeRuntime owns a reference to the given owned object, |
148 | | - // keeping it alive for use by the compiled code. Transfer ownership of the |
149 | | - // object to the CodeRuntime. |
150 | | - void addReference(Ref<>&& obj); |
151 | | - |
152 | 107 | // Ensure that this CodeRuntime owns a reference to the given borrowed |
153 | 108 | // object, keeping it alive for use by the compiled code. Make CodeRuntime a |
154 | 109 | // new owner of the object. |
155 | 110 | void addReference(BorrowedRef<> obj); |
156 | 111 |
|
| 112 | + // Release any references this CodeRuntime holds to Python objects. |
| 113 | + void releaseReferences(); |
| 114 | + |
157 | 115 | // Store meta-data about generator yield point. |
158 | | - GenYieldPoint* addGenYieldPoint(GenYieldPoint&& gen_yield_point) { |
159 | | - gen_yield_points_.emplace_back(std::move(gen_yield_point)); |
160 | | - return &gen_yield_points_.back(); |
161 | | - } |
| 116 | + GenYieldPoint* addGenYieldPoint(GenYieldPoint&& gen_yield_point); |
162 | 117 |
|
163 | | - void set_frame_size(int size) { |
164 | | - frame_size_ = size; |
165 | | - } |
166 | | - int frame_size() const { |
167 | | - return frame_size_; |
168 | | - } |
| 118 | + // Get the top-level runtime frame state for this CodeRuntime's PyCodeObject. |
| 119 | + const RuntimeFrameState* frameState() const; |
169 | 120 |
|
170 | | - DebugInfo* debug_info() { |
171 | | - return &debug_info_; |
172 | | - } |
| 121 | + // Get and set the total size of a stack frame for this compiled code object. |
| 122 | + int frameSize() const; |
| 123 | + void setFrameSize(int size); |
173 | 124 |
|
174 | | - static constexpr int64_t frameStateOffset() { |
175 | | -#pragma GCC diagnostic push |
176 | | -#pragma GCC diagnostic ignored "-Winvalid-offsetof" |
177 | | - return offsetof(CodeRuntime, frame_state_); |
178 | | -#pragma GCC diagnostic pop |
179 | | - } |
180 | | - |
181 | | - static const int64_t kPyCodeOffset; |
| 125 | + DebugInfo* debugInfo(); |
182 | 126 |
|
183 | 127 | private: |
184 | 128 | RuntimeFrameState frame_state_; |
185 | 129 | std::vector<std::unique_ptr<RuntimeFrameState>> inlined_frame_states_; |
186 | 130 |
|
| 131 | + // References owned by this CodeRuntime. |
187 | 132 | std::unordered_set<ThreadedRef<PyObject>> references_; |
188 | 133 |
|
189 | 134 | // Metadata about yield points. Deque so we can have raw pointers to content. |
190 | 135 | std::deque<GenYieldPoint> gen_yield_points_; |
191 | 136 |
|
192 | 137 | int frame_size_{-1}; |
193 | | - |
194 | 138 | DebugInfo debug_info_; |
195 | 139 | }; |
196 | 140 |
|
|
0 commit comments