PageRenderTime 225ms CodeModel.GetById 100ms app.highlight 14ms RepoModel.GetById 107ms app.codeStats 0ms

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