OLD | NEW |
1 #include "Python.h" | 1 #include "Python.h" |
2 #include "JIT/RuntimeFeedback.h" | 2 #include "JIT/RuntimeFeedback.h" |
3 | 3 |
4 #include "llvm/ADT/PointerIntPair.h" | 4 #include "llvm/ADT/PointerIntPair.h" |
5 #include "llvm/ADT/STLExtras.h" | 5 #include "llvm/ADT/STLExtras.h" |
6 #include "llvm/ADT/SmallPtrSet.h" | 6 #include "llvm/ADT/SmallPtrSet.h" |
7 #include "llvm/ADT/SmallVector.h" | 7 #include "llvm/ADT/SmallVector.h" |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 using llvm::PointerIntPair; | 11 using llvm::PointerIntPair; |
12 using llvm::PointerLikeTypeTraits; | 12 using llvm::PointerLikeTypeTraits; |
13 using llvm::SmallPtrSet; | 13 using llvm::SmallPtrSet; |
14 using llvm::SmallVector; | 14 using llvm::SmallVector; |
15 | 15 |
16 | 16 |
17 static bool | |
18 is_duplicate_method(PyObject *a, PyMethodDef *b) | |
19 { | |
20 return PyCFunction_Check(a) && PyCFunction_GET_FUNCTION(a) == b->ml_meth; | |
21 } | |
22 | |
23 PyLimitedFeedback::PyLimitedFeedback() | 17 PyLimitedFeedback::PyLimitedFeedback() |
24 { | 18 { |
25 } | 19 } |
26 | 20 |
27 PyLimitedFeedback::PyLimitedFeedback(const PyLimitedFeedback &src) | 21 PyLimitedFeedback::PyLimitedFeedback(const PyLimitedFeedback &src) |
28 { | 22 { |
29 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { | 23 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { |
30 if (src.InObjectMode()) { | 24 if (src.InObjectMode()) { |
31 PyObject *value = (PyObject *)src.data_[i].getPointer(); | 25 PyObject *value = (PyObject *)src.data_[i].getPointer(); |
32 Py_XINCREF(value); | 26 Py_XINCREF(value); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 void *counter_as_pointer = this->data_[counter_id].getPointer(); | 99 void *counter_as_pointer = this->data_[counter_id].getPointer(); |
106 return reinterpret_cast<uintptr_t>(counter_as_pointer) >> shift; | 100 return reinterpret_cast<uintptr_t>(counter_as_pointer) >> shift; |
107 } | 101 } |
108 | 102 |
109 void | 103 void |
110 PyLimitedFeedback::Clear() | 104 PyLimitedFeedback::Clear() |
111 { | 105 { |
112 bool object_mode = this->InObjectMode(); | 106 bool object_mode = this->InObjectMode(); |
113 | 107 |
114 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { | 108 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { |
115 if (object_mode) | 109 if (object_mode) { |
116 Py_XDECREF((PyObject *)this->data_[i].getPointer()); | 110 Py_XDECREF((PyObject *)this->data_[i].getPointer()); |
| 111 } |
117 this->data_[i].setPointer(NULL); | 112 this->data_[i].setPointer(NULL); |
118 this->data_[i].setInt(0); | 113 this->data_[i].setInt(0); |
119 } | 114 } |
120 } | 115 } |
121 | 116 |
122 void | 117 void |
123 PyLimitedFeedback::AddObjectSeen(PyObject *obj) | 118 PyLimitedFeedback::AddObjectSeen(PyObject *obj) |
124 { | 119 { |
125 assert(this->InObjectMode()); | 120 assert(this->InObjectMode()); |
126 this->SetFlagBit(OBJECT_MODE_BIT, true); | 121 this->SetFlagBit(OBJECT_MODE_BIT, true); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 { | 161 { |
167 assert(this->InFuncMode()); | 162 assert(this->InFuncMode()); |
168 this->SetFlagBit(FUNC_MODE_BIT, true); | 163 this->SetFlagBit(FUNC_MODE_BIT, true); |
169 | 164 |
170 if (this->GetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT)) | 165 if (this->GetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT)) |
171 return; | 166 return; |
172 if (obj == NULL) { | 167 if (obj == NULL) { |
173 this->SetFlagBit(SAW_A_NULL_OBJECT_BIT, true); | 168 this->SetFlagBit(SAW_A_NULL_OBJECT_BIT, true); |
174 return; | 169 return; |
175 } | 170 } |
176 if (!PyCFunction_Check(obj)) | |
177 return; | |
178 | 171 |
179 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { | 172 // Record the type of the function, and the methoddef if it's a call to a C |
180 PyMethodDef *value = (PyMethodDef *)this->data_[i].getPointer(); | 173 // function. |
181 if (value == NULL) { | 174 PyTypeObject *type = Py_TYPE(obj); |
182 this->data_[i].setPointer((void *)PyCFunction_GET_METHODDEF(obj)); | 175 PyMethodDef *ml = NULL; |
183 return; | 176 if (PyCFunction_Check(obj)) { |
184 } | 177 ml = PyCFunction_GET_METHODDEF(obj); |
185 // Deal with the fact that "for x in y: l.append(x)" results in· | 178 } else if (PyMethodDescr_Check(obj)) { |
186 // multiple method objects for l.append. | 179 ml = ((PyMethodDescrObject *)obj)->d_method; |
187 if (is_duplicate_method(obj, value)) | |
188 return; | |
189 } | 180 } |
190 // Record overflow. | 181 |
191 this->SetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT, true); | 182 PyTypeObject *old_type = (PyTypeObject *)this->data_[0].getPointer(); |
| 183 PyMethodDef *old_ml = (PyMethodDef *)this->data_[1].getPointer(); |
| 184 if (old_type == NULL) { |
| 185 // Record this method. |
| 186 Py_INCREF(type); |
| 187 this->data_[0].setPointer((void*)type); |
| 188 this->data_[1].setPointer((void*)ml); |
| 189 } else if (old_type != type || old_ml != ml) { |
| 190 // We found something else here already. Set this flag to indicate the |
| 191 // call site is polymorphic, even if we haven't seen more than three |
| 192 // objects. |
| 193 this->SetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT, true); |
| 194 } |
| 195 // The call site is monomorphic, so we leave it as is. |
192 } | 196 } |
193 | 197 |
194 void | 198 void |
195 PyLimitedFeedback::GetSeenFuncsInto( | 199 PyLimitedFeedback::GetSeenFuncsInto( |
196 SmallVector<PyMethodDef*, 3> &result) const | 200 SmallVector<PyTypeMethodPair, 3> &result) const |
197 { | 201 { |
198 assert(this->InFuncMode()); | 202 assert(this->InFuncMode()); |
199 | 203 |
200 result.clear(); | 204 result.clear(); |
201 if (this->GetFlagBit(SAW_A_NULL_OBJECT_BIT)) { | 205 if (this->GetFlagBit(SAW_A_NULL_OBJECT_BIT)) { |
202 // Saw a NULL value, so add NULL to the result. | 206 // Saw a NULL value, so add NULL to the result. |
203 result.push_back(NULL); | 207 result.push_back( |
| 208 std::make_pair<PyTypeObject*, PyMethodDef*>(NULL, NULL)); |
204 } | 209 } |
205 for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) { | 210 PyTypeObject *type = (PyTypeObject *)this->data_[0].getPointer(); |
206 PyMethodDef *value = (PyMethodDef *)this->data_[i].getPointer(); | 211 PyMethodDef *ml = (PyMethodDef *)this->data_[1].getPointer(); |
207 if (value == NULL) | 212 result.push_back(std::make_pair<PyTypeObject*, PyMethodDef*>(type, ml)); |
208 return; | |
209 result.push_back(value); | |
210 } | |
211 } | 213 } |
212 | 214 |
213 | 215 |
214 PyFullFeedback::PyFullFeedback() | 216 PyFullFeedback::PyFullFeedback() |
215 : counters_(/* Zero out the array. */), | 217 : counters_(/* Zero out the array. */), |
216 usage_(UnknownMode) | 218 usage_(UnknownMode) |
217 { | 219 { |
218 } | 220 } |
219 | 221 |
220 PyFullFeedback::PyFullFeedback(const PyFullFeedback &src) | 222 PyFullFeedback::PyFullFeedback(const PyFullFeedback &src) |
221 { | 223 { |
222 this->usage_ = src.usage_; | 224 this->usage_ = src.usage_; |
223 for (unsigned i = 0; i < llvm::array_lengthof(this->counters_); ++i) | 225 for (unsigned i = 0; i < llvm::array_lengthof(this->counters_); ++i) |
224 this->counters_[i] = src.counters_[i]; | 226 this->counters_[i] = src.counters_[i]; |
225 for (ObjSet::iterator it = src.data_.begin(), end = src.data_.end(); | 227 for (ObjSet::iterator it = src.data_.begin(), end = src.data_.end(); |
226 it != end; ++it) { | 228 it != end; ++it) { |
227 void *obj = *it; | 229 void *obj = *it; |
228 if (src.usage_ == ObjectMode) { | 230 if (src.usage_ == ObjectMode) { |
229 Py_XINCREF((PyObject *)obj); | 231 Py_XINCREF((PyObject *)obj); |
230 } | 232 } |
231 this->data_.insert(obj); | 233 this->data_.insert(obj); |
232 } | 234 } |
233 } | 235 } |
234 | 236 |
235 PyFullFeedback::~PyFullFeedback() | 237 PyFullFeedback::~PyFullFeedback() |
236 { | 238 { |
| 239 if (this->InFuncMode()) { |
| 240 // We have to free these pairs if we're in func mode. |
| 241 for (ObjSet::const_iterator it = this->data_.begin(), |
| 242 end = this->data_.end(); it != end; ++it) { |
| 243 delete (PyTypeMethodPair*)*it; |
| 244 } |
| 245 } |
237 this->Clear(); | 246 this->Clear(); |
238 } | 247 } |
239 | 248 |
240 PyFullFeedback & | 249 PyFullFeedback & |
241 PyFullFeedback::operator=(PyFullFeedback rhs) | 250 PyFullFeedback::operator=(PyFullFeedback rhs) |
242 { | 251 { |
243 this->Swap(&rhs); | 252 this->Swap(&rhs); |
244 return *this; | 253 return *this; |
245 } | 254 } |
246 | 255 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 result.push_back((PyObject *)*it); | 306 result.push_back((PyObject *)*it); |
298 } | 307 } |
299 } | 308 } |
300 | 309 |
301 void | 310 void |
302 PyFullFeedback::AddFuncSeen(PyObject *obj) | 311 PyFullFeedback::AddFuncSeen(PyObject *obj) |
303 { | 312 { |
304 assert(this->InFuncMode()); | 313 assert(this->InFuncMode()); |
305 this->usage_ = FuncMode; | 314 this->usage_ = FuncMode; |
306 | 315 |
307 // We only record C functions for now. | 316 PyMethodDef *ml = NULL; |
308 if (!PyCFunction_Check(obj)) | 317 PyTypeObject *type = NULL; |
309 return; | 318 if (obj != NULL) { |
310 if (obj == NULL) | 319 type = Py_TYPE(obj); |
311 this->data_.insert(NULL); | 320 |
312 else if (!this->data_.count(obj)) { | 321 // We only record a methoddef if this is a C function. |
313 // Deal with the fact that "for x in y: l.append(x)" results in· | 322 if (PyCFunction_Check(obj)) { |
314 // multiple method objects for l.append. | 323 ml = PyCFunction_GET_METHODDEF(obj); |
315 for (ObjSet::const_iterator it = this->data_.begin(), | 324 } else if (PyMethodDescr_Check(obj)) { |
316 end = this->data_.end(); it != end; ++it) { | 325 ml = ((PyMethodDescrObject *)obj)->d_method; |
317 if (is_duplicate_method(obj, (PyMethodDef *)*it)) | |
318 return; | |
319 } | 326 } |
| 327 } |
320 | 328 |
321 this->data_.insert((void *)PyCFunction_GET_METHODDEF(obj)); | 329 for (ObjSet::const_iterator it = this->data_.begin(), |
| 330 end = this->data_.end(); it != end; ++it) { |
| 331 PyTypeMethodPair *pair = (PyTypeMethodPair*)*it; |
| 332 if (pair->first == type && pair->second == ml) |
| 333 return; |
322 } | 334 } |
| 335 |
| 336 PyTypeMethodPair *pair = new PyTypeMethodPair(type, ml); |
| 337 this->data_.insert((void *)pair); |
323 } | 338 } |
324 | 339 |
325 void | 340 void |
326 PyFullFeedback::GetSeenFuncsInto( | 341 PyFullFeedback::GetSeenFuncsInto( |
327 SmallVector<PyMethodDef*, /*in-object elems=*/3> &result) const | 342 SmallVector<PyTypeMethodPair, 3> &result) const |
328 { | 343 { |
329 assert(this->InFuncMode()); | 344 assert(this->InFuncMode()); |
330 | 345 |
331 result.clear(); | 346 result.clear(); |
332 for (ObjSet::const_iterator it = this->data_.begin(), | 347 for (ObjSet::const_iterator it = this->data_.begin(), |
333 end = this->data_.end(); it != end; ++it) { | 348 end = this->data_.end(); it != end; ++it) { |
334 result.push_back((PyMethodDef *)*it); | 349 result.push_back(*((PyTypeMethodPair *)*it)); |
335 } | 350 } |
336 } | 351 } |
337 | 352 |
338 void | 353 void |
339 PyFullFeedback::IncCounter(unsigned counter_id) | 354 PyFullFeedback::IncCounter(unsigned counter_id) |
340 { | 355 { |
341 assert(this->InCounterMode()); | 356 assert(this->InCounterMode()); |
342 assert(counter_id < llvm::array_lengthof(this->counters_)); | 357 assert(counter_id < llvm::array_lengthof(this->counters_)); |
343 this->usage_ = CounterMode; | 358 this->usage_ = CounterMode; |
344 | 359 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 } | 410 } |
396 | 411 |
397 void | 412 void |
398 PyFeedbackMap::Clear() | 413 PyFeedbackMap::Clear() |
399 { | 414 { |
400 for (FeedbackMap::iterator it = this->entries_.begin(), | 415 for (FeedbackMap::iterator it = this->entries_.begin(), |
401 end = this->entries_.end(); it != end; ++it) { | 416 end = this->entries_.end(); it != end; ++it) { |
402 it->second.Clear(); | 417 it->second.Clear(); |
403 } | 418 } |
404 } | 419 } |
OLD | NEW |