#include <assert.h>
+#include <stdlib.h>
#include <map>
#include <vector>
-#include <iostream>
-namespace Trace {
+namespace trace {
typedef unsigned Id;
};
-struct EnumSig {
- Id id;
+struct EnumValue {
const char *name;
signed long long value;
};
+struct EnumSig {
+ Id id;
+ unsigned num_values;
+ const EnumValue *values;
+};
+
+
struct BitmaskFlag {
const char *name;
unsigned long long value;
virtual const char *toString(void) const;
const Value & operator[](size_t index) const;
-
- void dump(std::ostream &os, bool color=true);
};
class Float : public Value
{
public:
- Float(double _value) : value(_value) {}
+ Float(float _value) : value(_value) {}
+
+ bool toBool(void) const;
+ signed long long toSInt(void) const;
+ unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+ void visit(Visitor &visitor);
+
+ float value;
+};
+
+
+class Double : public Value
+{
+public:
+ Double(double _value) : value(_value) {}
bool toBool(void) const;
signed long long toSInt(void) const;
};
-class Enum : public Value
+class Enum : public SInt
{
public:
- Enum(const EnumSig *_sig) : sig(_sig) {}
+ Enum(const EnumSig *_sig, signed long long _value) : SInt(_value), sig(_sig) {}
- bool toBool(void) const;
- signed long long toSInt(void) const;
- unsigned long long toUInt(void) const;
- virtual float toFloat(void) const;
- virtual double toDouble(void) const;
void visit(Visitor &visitor);
const EnumSig *sig;
+
+ const EnumValue *
+ lookup() {
+ // TODO: use a std::map
+ for (const EnumValue *it = sig->values; it != sig->values + sig->num_values; ++it) {
+ if (it->value == value) {
+ return it;
+ }
+ }
+ return NULL;
+ }
};
void visit(Visitor &visitor);
std::vector<Value *> values;
+
+ inline size_t
+ size(void) const {
+ return values.size();
+ }
};
};
+class Repr : public Value
+{
+public:
+ Repr(Value *human, Value *machine) :
+ humanValue(human),
+ machineValue(machine)
+ {}
+
+ /** Human-readible value */
+ Value *humanValue;
+
+ /** Machine-readible value */
+ Value *machineValue;
+
+ virtual bool toBool(void) const;
+ virtual signed long long toSInt(void) const;
+ virtual unsigned long long toUInt(void) const;
+ virtual float toFloat(void) const;
+ virtual double toDouble(void) const;
+
+ virtual void *toPointer(void) const;
+ virtual void *toPointer(bool bind);
+ virtual unsigned long long toUIntPtr(void) const;
+ virtual const char *toString(void) const;
+
+ void visit(Visitor &visitor);
+};
+
+
class Visitor
{
public:
virtual void visit(SInt *);
virtual void visit(UInt *);
virtual void visit(Float *);
+ virtual void visit(Double *);
virtual void visit(String *);
virtual void visit(Enum *);
virtual void visit(Bitmask *);
virtual void visit(Array *);
virtual void visit(Blob *);
virtual void visit(Pointer *);
+ virtual void visit(Repr *);
protected:
inline void _visit(Value *value) {
};
-inline std::ostream & operator <<(std::ostream &os, Value *value) {
- if (value) {
- value->dump(os);
- }
- return os;
-}
+typedef unsigned CallFlags;
+
+/**
+ * Call flags.
+ *
+ * TODO: It might be better to to record some of these (but not all) into the
+ * trace file.
+ */
+enum {
+
+ /**
+ * Whether a call was really done by the application or not.
+ *
+ * This flag is set for fake calls -- calls not truly done by the application
+ * but emitted and recorded for completeness, to provide contextual information
+ * necessary for retracing, that would not be available through other ways.
+ *
+ * XXX: This one definetely needs to go into the trace file.
+ */
+ CALL_FLAG_FAKE = (1 << 0),
+
+ /**
+ * Whether this call should be retraced or ignored.
+ *
+ * This flag is set for calls which can't be safely replayed (due to incomplete
+ * information) or that have no sideffects.
+ *
+ * Some incomplete calls are unreproduceable, but not all.
+ */
+ CALL_FLAG_NON_REPRODUCIBLE = (1 << 1),
+
+ /**
+ * Whether this call has no side-effects, therefore don't need to be
+ * retraced.
+ *
+ * This flag is set for calls that merely query information which is not
+ * needed for posterior calls.
+ */
+ CALL_FLAG_NO_SIDE_EFFECTS = (1 << 2),
+
+ /**
+ * Whether this call renders into the bound rendertargets.
+ */
+ CALL_FLAG_RENDER = (1 << 3),
+
+ /**
+ * Whether this call causes render target to be swapped.
+ *
+ * This does not mark frame termination by itself -- that's solely the
+ * responsibility of `endOfFrame` bit.
+ *
+ * This mean that snapshots should be take prior to the call, and not
+ * after.
+ */
+ CALL_FLAG_SWAP_RENDERTARGET = (1 << 4),
+
+ /**
+ * Whether this call terminates a frame.
+ *
+ * XXX: This can't always be determined by the function name, so it should also
+ * go into the trace file eventually.
+ */
+ CALL_FLAG_END_FRAME = (1 << 5),
+
+ /**
+ * Whether this call is incomplete, i.e., it never returned.
+ */
+ CALL_FLAG_INCOMPLETE = (1 << 6),
+
+ /**
+ * Whether this call is verbose (i.e., not usually interesting).
+ */
+ CALL_FLAG_VERBOSE = (1 << 7),
+};
+
+
+struct Arg
+{
+ Value *value;
+};
class Call
{
public:
+ unsigned thread_id;
unsigned no;
const FunctionSig *sig;
- std::vector<Value *> args;
+ std::vector<Arg> args;
Value *ret;
- Call(FunctionSig *_sig) : sig(_sig), args(_sig->num_args), ret(0) { }
+ CallFlags flags;
+
+ Call(FunctionSig *_sig, const CallFlags &_flags, unsigned _thread_id) :
+ thread_id(_thread_id),
+ sig(_sig),
+ args(_sig->num_args),
+ ret(0),
+ flags(_flags) {
+ }
+
~Call();
inline const char * name(void) const {
inline Value & arg(unsigned index) {
assert(index < args.size());
- return *(args[index]);
+ return *(args[index].value);
}
-
- void dump(std::ostream &os, bool color=true);
};
-inline std::ostream & operator <<(std::ostream &os, Call &call) {
- call.dump(os);
- return os;
-}
-
-
-} /* namespace Trace */
+} /* namespace trace */
#endif /* _TRACE_MODEL_HPP_ */