/JIT/RuntimeFeedback.h

http://unladen-swallow.googlecode.com/ · C Header · 206 lines · 112 code · 35 blank · 59 comment · 12 complexity · 2e264ce05369f00393b61be7a29e3f0f MD5 · raw file

  1. // -*- C++ -*-
  2. //
  3. // This file defines PyRuntimeFeedback as the basic unit of feedback
  4. // data. Each instance of Py{Limited,Full}Feedback is capable of operating
  5. // in one of several modes: recording Python objects, incrementing a set of
  6. // counters, or recording called functions. These modes are mutually exclusive,
  7. // and attempting to mix them is a fatal error.
  8. //
  9. // Use the AddObjectSeen(), GetSeenObjectsInto(), and ObjectsOverflowed()
  10. // methods to store objects; the IncCounter() and GetCounter() methods to access
  11. // the counters; or the AddFuncSeen(), GetSeenFuncsInto(), and FuncsOverflowed()
  12. // methods to store called functions.
  13. //
  14. // We provide two implementations of this interface to make it easy to
  15. // switch between a memory-efficient representation and a
  16. // representation that can store all the data we could possibly
  17. // collect. PyLimitedFeedback stores up to three objects, while
  18. // PyFullFeedback uses an unbounded set.
  19. #ifndef UTIL_RUNTIMEFEEDBACK_H
  20. #define UTIL_RUNTIMEFEEDBACK_H
  21. #ifndef __cplusplus
  22. #error This header expects to be included only in C++ source
  23. #endif
  24. #include "RuntimeFeedback_fwd.h"
  25. #include "llvm/ADT/DenseMap.h"
  26. #include "llvm/ADT/PointerIntPair.h"
  27. #include "llvm/ADT/SmallPtrSet.h"
  28. #include <string>
  29. namespace llvm {
  30. template<typename, unsigned> class SmallVector;
  31. }
  32. typedef std::pair<PyTypeObject*, PyMethodDef*> PyTypeMethodPair;
  33. // These are the counters used for feedback in the JUMP_IF opcodes.
  34. // The number of boolean inputs can be computed as (PY_FDO_JUMP_TRUE +
  35. // PY_FDO_JUMP_FALSE - PY_FDO_JUMP_NON_BOOLEAN).
  36. enum { PY_FDO_JUMP_TRUE = 0, PY_FDO_JUMP_FALSE, PY_FDO_JUMP_NON_BOOLEAN };
  37. // These are the counters used for feedback in the LOAD_METHOD opcode.
  38. enum { PY_FDO_LOADMETHOD_METHOD = 0, PY_FDO_LOADMETHOD_OTHER };
  39. class PyLimitedFeedback {
  40. public:
  41. PyLimitedFeedback();
  42. PyLimitedFeedback(const PyLimitedFeedback &src);
  43. ~PyLimitedFeedback();
  44. // Records that obj has been seen.
  45. void AddObjectSeen(PyObject *obj);
  46. // Clears result and fills it with the set of seen objects.
  47. void GetSeenObjectsInto(llvm::SmallVector<PyObject*, 3> &result) const;
  48. bool ObjectsOverflowed() const {
  49. return GetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT);
  50. }
  51. // Record that a given function was called.
  52. void AddFuncSeen(PyObject *obj);
  53. // Clears result and fills it with the set of observed types and
  54. // PyMethodDefs.
  55. void GetSeenFuncsInto(llvm::SmallVector<PyTypeMethodPair, 3> &result) const;
  56. bool FuncsOverflowed() const {
  57. return GetFlagBit(SAW_MORE_THAN_THREE_OBJS_BIT);
  58. }
  59. // There are three counters available. Their storage space
  60. // overlaps with the object record, so you can't use both. They
  61. // saturate rather than wrapping on overflow.
  62. void IncCounter(unsigned counter_id);
  63. uintptr_t GetCounter(unsigned counter_id) const;
  64. // Clears out the collected objects, functions and counters.
  65. void Clear();
  66. // Assignment copies the list of collected objects, fixing up refcounts.
  67. PyLimitedFeedback &operator=(PyLimitedFeedback rhs);
  68. private:
  69. // 'index' must be between 0 and 5 inclusive.
  70. void SetFlagBit(unsigned index, bool value);
  71. bool GetFlagBit(unsigned index) const;
  72. void Swap(PyLimitedFeedback *other);
  73. enum { NUM_POINTERS = 3 };
  74. enum Bits {
  75. // We have 6 bits available here to use to store flags (we get 2
  76. // bits at the bottom of each pointer on 32-bit systems, where
  77. // objects are generally aligned to 4-byte boundaries). These are
  78. // used as follows:
  79. // 0: True if we saw more than 3 objects.
  80. SAW_MORE_THAN_THREE_OBJS_BIT = 0,
  81. // 1: True if we got a NULL object.
  82. SAW_A_NULL_OBJECT_BIT = 1,
  83. // 2: True if this instance is being used in counter mode.
  84. COUNTER_MODE_BIT = 2,
  85. // 3: True if this instance is being used in object-gathering mode.
  86. OBJECT_MODE_BIT = 3,
  87. // 4: True if this instance is being used in function-gathering mode.
  88. FUNC_MODE_BIT = 4,
  89. // 5: Unused.
  90. };
  91. //
  92. // The pointers in this array start out NULL and are filled from
  93. // the lowest index as we see new objects. We store either PyObject *s (when
  94. // operating in object mode) or PyMethodDef *s (in function mode).
  95. llvm::PointerIntPair<void*, /*bits used from bottom of pointer=*/2>
  96. data_[NUM_POINTERS];
  97. bool InObjectMode() const {
  98. return GetFlagBit(OBJECT_MODE_BIT) ||
  99. !(GetFlagBit(COUNTER_MODE_BIT) || GetFlagBit(FUNC_MODE_BIT));
  100. }
  101. bool InCounterMode() const {
  102. return GetFlagBit(COUNTER_MODE_BIT) ||
  103. !(GetFlagBit(OBJECT_MODE_BIT) || GetFlagBit(FUNC_MODE_BIT));
  104. }
  105. bool InFuncMode() const {
  106. return GetFlagBit(FUNC_MODE_BIT) ||
  107. !(GetFlagBit(OBJECT_MODE_BIT) || GetFlagBit(COUNTER_MODE_BIT));
  108. }
  109. };
  110. class PyFullFeedback {
  111. public:
  112. PyFullFeedback();
  113. PyFullFeedback(const PyFullFeedback &src);
  114. ~PyFullFeedback();
  115. // Records that obj has been seen.
  116. void AddObjectSeen(PyObject *obj);
  117. // Clears result and fills it with the set of seen objects.
  118. void GetSeenObjectsInto(llvm::SmallVector<PyObject*, 3> &result) const;
  119. bool ObjectsOverflowed() const { return false; }
  120. // Record that a given function was called.
  121. void AddFuncSeen(PyObject *obj);
  122. // Clears result and fills it with the set of observed types and
  123. // PyMethodDefs.
  124. void GetSeenFuncsInto(llvm::SmallVector<PyTypeMethodPair, 3> &result) const;
  125. bool FuncsOverflowed() const { return false; }
  126. void IncCounter(unsigned counter_id);
  127. uintptr_t GetCounter(unsigned counter_id) const;
  128. // Clears out the collected objects and counters.
  129. void Clear();
  130. // Assignment copies the list of collected objects, fixing up refcounts.
  131. PyFullFeedback &operator=(PyFullFeedback rhs);
  132. private:
  133. // Assume three pointers in the set to start with. We store either
  134. // PyObject *s (when in object mode) or pairs of types and PyMethodDef *s
  135. // (when in function mode).
  136. typedef llvm::SmallPtrSet<void*, 3> ObjSet;
  137. void Swap(PyFullFeedback *other);
  138. ObjSet data_;
  139. uintptr_t counters_[3];
  140. enum UsageMode {
  141. UnknownMode,
  142. CounterMode,
  143. ObjectMode,
  144. FuncMode,
  145. };
  146. UsageMode usage_;
  147. bool InObjectMode() const {
  148. return usage_ == ObjectMode || usage_ == UnknownMode;
  149. }
  150. bool InFuncMode() const {
  151. return usage_ == FuncMode || usage_ == UnknownMode;
  152. }
  153. bool InCounterMode() const {
  154. return usage_ == CounterMode || usage_ == UnknownMode;
  155. }
  156. };
  157. typedef PyLimitedFeedback PyRuntimeFeedback;
  158. // "struct" to make C and VC++ happy at the same time.
  159. struct PyFeedbackMap {
  160. PyRuntimeFeedback &GetOrCreateFeedbackEntry(
  161. unsigned opcode_index, unsigned arg_index);
  162. const PyRuntimeFeedback *GetFeedbackEntry(
  163. unsigned opcode_index, unsigned arg_index) const;
  164. void Clear();
  165. private:
  166. // The key is a (opcode_index, arg_index) pair.
  167. typedef std::pair<unsigned, unsigned> FeedbackKey;
  168. typedef llvm::DenseMap<FeedbackKey, PyRuntimeFeedback> FeedbackMap;
  169. FeedbackMap entries_;
  170. };
  171. #endif // UTIL_RUNTIMEFEEDBACK_H