/JIT/RuntimeFeedback.cc

http://unladen-swallow.googlecode.com/ · C++ · 423 lines · 353 code · 56 blank · 14 comment · 71 complexity · 2d8c3b1877002196f1b1c4fa4c7e2bd0 MD5 · raw file

  1. #include "Python.h"
  2. #include "JIT/RuntimeFeedback.h"
  3. #include "llvm/ADT/PointerIntPair.h"
  4. #include "llvm/ADT/STLExtras.h"
  5. #include "llvm/ADT/SmallPtrSet.h"
  6. #include "llvm/ADT/SmallVector.h"
  7. #include <algorithm>
  8. using llvm::PointerIntPair;
  9. using llvm::PointerLikeTypeTraits;
  10. using llvm::SmallPtrSet;
  11. using llvm::SmallVector;
  12. PyLimitedFeedback::PyLimitedFeedback()
  13. {
  14. }
  15. PyLimitedFeedback::PyLimitedFeedback(const PyLimitedFeedback &src)
  16. {
  17. for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) {
  18. if (src.InObjectMode()) {
  19. PyObject *value = (PyObject *)src.data_[i].getPointer();
  20. Py_XINCREF(value);
  21. this->data_[i] = src.data_[i];
  22. }
  23. else {
  24. this->data_[i] = src.data_[i];
  25. }
  26. }
  27. }
  28. PyLimitedFeedback::~PyLimitedFeedback()
  29. {
  30. this->Clear();
  31. }
  32. PyLimitedFeedback &
  33. PyLimitedFeedback::operator=(PyLimitedFeedback rhs)
  34. {
  35. this->Swap(&rhs);
  36. return *this;
  37. }
  38. void
  39. PyLimitedFeedback::Swap(PyLimitedFeedback *other)
  40. {
  41. for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) {
  42. std::swap(this->data_[i], other->data_[i]);
  43. }
  44. }
  45. void
  46. PyLimitedFeedback::SetFlagBit(unsigned index, bool value)
  47. {
  48. assert(index < 6);
  49. PointerIntPair<void*, 2>& slot = this->data_[index / 2];
  50. unsigned mask = 1 << (index % 2);
  51. unsigned old_value = slot.getInt();
  52. unsigned new_value = (old_value & ~mask) | (value << (index % 2));
  53. slot.setInt(new_value);
  54. }
  55. bool
  56. PyLimitedFeedback::GetFlagBit(unsigned index) const
  57. {
  58. assert(index < 6);
  59. const PointerIntPair<void*, 2>& slot = this->data_[index / 2];
  60. unsigned value = slot.getInt();
  61. return (value >> (index % 2)) & 1;
  62. }
  63. void
  64. PyLimitedFeedback::IncCounter(unsigned counter_id)
  65. {
  66. assert(this->InCounterMode());
  67. assert(counter_id < (unsigned)PyLimitedFeedback::NUM_POINTERS);
  68. this->SetFlagBit(COUNTER_MODE_BIT, true);
  69. uintptr_t old_value =
  70. reinterpret_cast<uintptr_t>(this->data_[counter_id].getPointer());
  71. uintptr_t shift = PointerLikeTypeTraits<PyObject*>::NumLowBitsAvailable;
  72. uintptr_t new_value = old_value + (1U << shift);
  73. if (new_value > old_value) {
  74. // Only increment if we're not saturated yet.
  75. this->data_[counter_id].setPointer(
  76. reinterpret_cast<void*>(new_value));
  77. }
  78. }
  79. uintptr_t
  80. PyLimitedFeedback::GetCounter(unsigned counter_id) const
  81. {
  82. assert(this->InCounterMode());
  83. uintptr_t shift = PointerLikeTypeTraits<PyObject*>::NumLowBitsAvailable;
  84. void *counter_as_pointer = this->data_[counter_id].getPointer();
  85. return reinterpret_cast<uintptr_t>(counter_as_pointer) >> shift;
  86. }
  87. void
  88. PyLimitedFeedback::Clear()
  89. {
  90. bool object_mode = this->InObjectMode();
  91. for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) {
  92. if (object_mode) {
  93. Py_XDECREF((PyObject *)this->data_[i].getPointer());
  94. }
  95. this->data_[i].setPointer(NULL);
  96. this->data_[i].setInt(0);
  97. }
  98. }
  99. void
  100. PyLimitedFeedback::AddObjectSeen(PyObject *obj)
  101. {
  102. assert(this->InObjectMode());
  103. this->SetFlagBit(OBJECT_MODE_BIT, true);
  104. if (obj == NULL) {
  105. SetFlagBit(SAW_A_NULL_OBJECT_BIT, true);
  106. return;
  107. }
  108. for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) {
  109. PyObject *value = (PyObject *)data_[i].getPointer();
  110. if (value == obj)
  111. return;
  112. if (value == NULL) {
  113. Py_INCREF(obj);
  114. data_[i].setPointer((void *)obj);
  115. return;
  116. }
  117. }
  118. // Record overflow.
  119. SetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT, true);
  120. }
  121. void
  122. PyLimitedFeedback::GetSeenObjectsInto(SmallVector<PyObject*, 3> &result) const
  123. {
  124. assert(this->InObjectMode());
  125. result.clear();
  126. if (GetFlagBit(SAW_A_NULL_OBJECT_BIT)) {
  127. // Saw a NULL value, so add NULL to the result.
  128. result.push_back(NULL);
  129. }
  130. for (int i = 0; i < PyLimitedFeedback::NUM_POINTERS; ++i) {
  131. PyObject *value = (PyObject *)data_[i].getPointer();
  132. if (value == NULL)
  133. return;
  134. result.push_back(value);
  135. }
  136. }
  137. void
  138. PyLimitedFeedback::AddFuncSeen(PyObject *obj)
  139. {
  140. assert(this->InFuncMode());
  141. this->SetFlagBit(FUNC_MODE_BIT, true);
  142. if (this->GetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT))
  143. return;
  144. if (obj == NULL) {
  145. this->SetFlagBit(SAW_A_NULL_OBJECT_BIT, true);
  146. return;
  147. }
  148. // Record the type of the function, and the methoddef if it's a call to a C
  149. // function.
  150. PyTypeObject *type = Py_TYPE(obj);
  151. PyMethodDef *ml = NULL;
  152. if (PyCFunction_Check(obj)) {
  153. ml = PyCFunction_GET_METHODDEF(obj);
  154. } else if (PyMethodDescr_Check(obj)) {
  155. ml = ((PyMethodDescrObject *)obj)->d_method;
  156. }
  157. PyTypeObject *old_type = (PyTypeObject *)this->data_[0].getPointer();
  158. PyMethodDef *old_ml = (PyMethodDef *)this->data_[1].getPointer();
  159. if (old_type == NULL) {
  160. // Record this method.
  161. Py_INCREF(type);
  162. this->data_[0].setPointer((void*)type);
  163. this->data_[1].setPointer((void*)ml);
  164. } else if (old_type != type || old_ml != ml) {
  165. // We found something else here already. Set this flag to indicate the
  166. // call site is polymorphic, even if we haven't seen more than three
  167. // objects.
  168. this->SetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT, true);
  169. }
  170. // The call site is monomorphic, so we leave it as is.
  171. }
  172. void
  173. PyLimitedFeedback::GetSeenFuncsInto(
  174. SmallVector<PyTypeMethodPair, 3> &result) const
  175. {
  176. assert(this->InFuncMode());
  177. result.clear();
  178. if (this->GetFlagBit(SAW_A_NULL_OBJECT_BIT)) {
  179. // Saw a NULL value, so add NULL to the result.
  180. result.push_back(
  181. std::make_pair<PyTypeObject*, PyMethodDef*>(NULL, NULL));
  182. }
  183. PyTypeObject *type = (PyTypeObject *)this->data_[0].getPointer();
  184. PyMethodDef *ml = (PyMethodDef *)this->data_[1].getPointer();
  185. result.push_back(std::make_pair<PyTypeObject*, PyMethodDef*>(type, ml));
  186. }
  187. PyFullFeedback::PyFullFeedback()
  188. : counters_(/* Zero out the array. */),
  189. usage_(UnknownMode)
  190. {
  191. }
  192. PyFullFeedback::PyFullFeedback(const PyFullFeedback &src)
  193. {
  194. this->usage_ = src.usage_;
  195. for (unsigned i = 0; i < llvm::array_lengthof(this->counters_); ++i)
  196. this->counters_[i] = src.counters_[i];
  197. for (ObjSet::iterator it = src.data_.begin(), end = src.data_.end();
  198. it != end; ++it) {
  199. void *obj = *it;
  200. if (src.usage_ == ObjectMode) {
  201. Py_XINCREF((PyObject *)obj);
  202. }
  203. else if (src.InFuncMode()) {
  204. PyTypeMethodPair &src_pair_ref = *(PyTypeMethodPair*)obj;
  205. obj = new PyTypeMethodPair(src_pair_ref);
  206. }
  207. this->data_.insert(obj);
  208. }
  209. }
  210. PyFullFeedback::~PyFullFeedback()
  211. {
  212. if (this->InFuncMode()) {
  213. // We have to free these pairs if we're in func mode.
  214. for (ObjSet::const_iterator it = this->data_.begin(),
  215. end = this->data_.end(); it != end; ++it) {
  216. delete (PyTypeMethodPair*)*it;
  217. }
  218. }
  219. this->Clear();
  220. }
  221. PyFullFeedback &
  222. PyFullFeedback::operator=(PyFullFeedback rhs)
  223. {
  224. this->Swap(&rhs);
  225. return *this;
  226. }
  227. void
  228. PyFullFeedback::Swap(PyFullFeedback *other)
  229. {
  230. std::swap(this->usage_, other->usage_);
  231. std::swap(this->data_, other->data_);
  232. for (unsigned i = 0; i < llvm::array_lengthof(this->counters_); ++i)
  233. std::swap(this->counters_[i], other->counters_[i]);
  234. }
  235. void
  236. PyFullFeedback::Clear()
  237. {
  238. for (ObjSet::iterator it = this->data_.begin(),
  239. end = this->data_.end(); it != end; ++it) {
  240. if (this->usage_ == ObjectMode) {
  241. Py_XDECREF((PyObject *)*it);
  242. }
  243. }
  244. this->data_.clear();
  245. for (unsigned i = 0; i < llvm::array_lengthof(this->counters_); ++i)
  246. this->counters_[i] = 0;
  247. this->usage_ = UnknownMode;
  248. }
  249. void
  250. PyFullFeedback::AddObjectSeen(PyObject *obj)
  251. {
  252. assert(this->InObjectMode());
  253. this->usage_ = ObjectMode;
  254. if (obj == NULL) {
  255. this->data_.insert(NULL);
  256. return;
  257. }
  258. if (!this->data_.count(obj)) {
  259. Py_INCREF(obj);
  260. this->data_.insert((void *)obj);
  261. }
  262. }
  263. void
  264. PyFullFeedback::GetSeenObjectsInto(
  265. SmallVector<PyObject*, /*in-object elems=*/3> &result) const
  266. {
  267. assert(this->InObjectMode());
  268. result.clear();
  269. for (ObjSet::const_iterator it = this->data_.begin(),
  270. end = this->data_.end(); it != end; ++it) {
  271. result.push_back((PyObject *)*it);
  272. }
  273. }
  274. void
  275. PyFullFeedback::AddFuncSeen(PyObject *obj)
  276. {
  277. assert(this->InFuncMode());
  278. this->usage_ = FuncMode;
  279. PyMethodDef *ml = NULL;
  280. PyTypeObject *type = NULL;
  281. if (obj != NULL) {
  282. type = Py_TYPE(obj);
  283. // We only record a methoddef if this is a C function.
  284. if (PyCFunction_Check(obj)) {
  285. ml = PyCFunction_GET_METHODDEF(obj);
  286. } else if (PyMethodDescr_Check(obj)) {
  287. ml = ((PyMethodDescrObject *)obj)->d_method;
  288. }
  289. }
  290. for (ObjSet::const_iterator it = this->data_.begin(),
  291. end = this->data_.end(); it != end; ++it) {
  292. PyTypeMethodPair *pair = (PyTypeMethodPair*)*it;
  293. if (pair->first == type && pair->second == ml)
  294. return;
  295. }
  296. PyTypeMethodPair *pair = new PyTypeMethodPair(type, ml);
  297. this->data_.insert((void *)pair);
  298. }
  299. void
  300. PyFullFeedback::GetSeenFuncsInto(
  301. SmallVector<PyTypeMethodPair, 3> &result) const
  302. {
  303. assert(this->InFuncMode());
  304. result.clear();
  305. for (ObjSet::const_iterator it = this->data_.begin(),
  306. end = this->data_.end(); it != end; ++it) {
  307. result.push_back(*((PyTypeMethodPair *)*it));
  308. }
  309. }
  310. void
  311. PyFullFeedback::IncCounter(unsigned counter_id)
  312. {
  313. assert(this->InCounterMode());
  314. assert(counter_id < llvm::array_lengthof(this->counters_));
  315. this->usage_ = CounterMode;
  316. uintptr_t old_value = this->counters_[counter_id];
  317. uintptr_t new_value = old_value + 1;
  318. if (new_value > old_value) {
  319. // Only increment if we're not saturated yet.
  320. this->counters_[counter_id] = new_value;
  321. }
  322. }
  323. uintptr_t
  324. PyFullFeedback::GetCounter(unsigned counter_id) const
  325. {
  326. assert(this->InCounterMode());
  327. return this->counters_[counter_id];
  328. }
  329. PyFeedbackMap *
  330. PyFeedbackMap_New()
  331. {
  332. return new PyFeedbackMap;
  333. }
  334. void
  335. PyFeedbackMap_Del(PyFeedbackMap *map)
  336. {
  337. delete map;
  338. }
  339. void
  340. PyFeedbackMap_Clear(PyFeedbackMap *map)
  341. {
  342. map->Clear();
  343. }
  344. const PyRuntimeFeedback *
  345. PyFeedbackMap::GetFeedbackEntry(unsigned opcode_index, unsigned arg_index) const
  346. {
  347. llvm::DenseMap<std::pair<unsigned, unsigned>,
  348. PyRuntimeFeedback>::const_iterator result =
  349. this->entries_.find(std::make_pair(opcode_index, arg_index));
  350. if (result == this->entries_.end())
  351. return NULL;
  352. return &result->second;
  353. }
  354. PyRuntimeFeedback &
  355. PyFeedbackMap::GetOrCreateFeedbackEntry(
  356. unsigned opcode_index, unsigned arg_index)
  357. {
  358. return this->entries_[std::make_pair(opcode_index, arg_index)];
  359. }
  360. void
  361. PyFeedbackMap::Clear()
  362. {
  363. for (FeedbackMap::iterator it = this->entries_.begin(),
  364. end = this->entries_.end(); it != end; ++it) {
  365. it->second.Clear();
  366. }
  367. }