summaryrefslogtreecommitdiff
path: root/lib/trace/trace_model.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/trace/trace_model.cpp')
-rw-r--r--lib/trace/trace_model.cpp301
1 files changed, 301 insertions, 0 deletions
diff --git a/lib/trace/trace_model.cpp b/lib/trace/trace_model.cpp
new file mode 100644
index 00000000..fbf3bdaa
--- /dev/null
+++ b/lib/trace/trace_model.cpp
@@ -0,0 +1,301 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include <string.h>
+#include <deque>
+
+#include "trace_model.hpp"
+
+
+namespace trace {
+
+
+static Null null;
+
+
+Call::~Call() {
+ for (auto & arg : args) {
+ delete arg.value;
+ }
+
+ if (ret) {
+ delete ret;
+ }
+}
+
+Value &
+Call::argByName(const char *argName) {
+ for (unsigned i = 0; i < sig->num_args; ++i) {
+ if (strcmp(sig->arg_names[i], argName) == 0) {
+ return arg(i);
+ }
+ }
+ return null;
+}
+
+
+String::~String() {
+ delete [] value;
+}
+
+
+WString::~WString() {
+ delete [] value;
+}
+
+
+Struct::~Struct() {
+ for (auto & member : members) {
+ delete member;
+ }
+}
+
+
+Array::~Array() {
+ for (auto & value : values) {
+ delete value;
+ }
+}
+
+
+#define BLOB_MAX_BOUND_SIZE (1*1024*1024*1024)
+
+class BoundBlob {
+public:
+ static size_t totalSize;
+
+private:
+ size_t size;
+ char *buf;
+
+public:
+ inline
+ BoundBlob(size_t _size, char *_buf) :
+ size(_size),
+ buf(_buf)
+ {
+ assert(totalSize + size >= totalSize);
+ totalSize += size;
+ }
+
+ inline
+ ~BoundBlob() {
+ assert(totalSize >= size);
+ totalSize -= size;
+ delete [] buf;
+ }
+
+ // Fake move constructor
+ // std::deque:push_back with move semantics was added only from c++11.
+ BoundBlob(const BoundBlob & other)
+ {
+ size = other.size;
+ buf = other.buf;
+ const_cast<BoundBlob &>(other).size = 0;
+ const_cast<BoundBlob &>(other).buf = 0;
+ }
+
+ // Disallow assignment operator
+ BoundBlob& operator = (const BoundBlob &);
+};
+
+size_t BoundBlob::totalSize = 0;
+
+typedef std::deque<BoundBlob> BoundBlobQueue;
+static BoundBlobQueue boundBlobQueue;
+
+
+Blob::~Blob() {
+ // Blobs are often bound and referred during many calls, so we can't delete
+ // them here in that case.
+ //
+ // Once bound there is no way to know when they were unbound, which
+ // effectively means we have to leak them. But some applications
+ // (particularly OpenGL applications that use vertex arrays in user memory)
+ // we can easily exhaust all memory. So instead we maintain a queue of
+ // bound blobs and keep the total size bounded.
+
+ if (!bound) {
+ delete [] buf;
+ return;
+ }
+
+ while (!boundBlobQueue.empty() &&
+ BoundBlob::totalSize + size > BLOB_MAX_BOUND_SIZE) {
+ boundBlobQueue.pop_front();
+ }
+
+ boundBlobQueue.push_back(BoundBlob(size, buf));
+}
+
+StackFrame::~StackFrame() {
+ if (module != NULL) {
+ delete [] module;
+ }
+ if (function != NULL) {
+ delete [] function;
+ }
+ if (filename != NULL) {
+ delete [] filename;
+ }
+}
+
+
+// bool cast
+bool Null ::toBool(void) const { return false; }
+bool Bool ::toBool(void) const { return value; }
+bool SInt ::toBool(void) const { return value != 0; }
+bool UInt ::toBool(void) const { return value != 0; }
+bool Float ::toBool(void) const { return value != 0; }
+bool Double ::toBool(void) const { return value != 0; }
+bool String ::toBool(void) const { return true; }
+bool WString::toBool(void) const { return true; }
+bool Struct ::toBool(void) const { return true; }
+bool Array ::toBool(void) const { return true; }
+bool Blob ::toBool(void) const { return true; }
+bool Pointer::toBool(void) const { return value != 0; }
+bool Repr ::toBool(void) const { return static_cast<bool>(machineValue); }
+
+
+// signed integer cast
+signed long long Value ::toSInt(void) const { assert(0); return 0; }
+signed long long Null ::toSInt(void) const { return 0; }
+signed long long Bool ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long SInt ::toSInt(void) const { return value; }
+signed long long UInt ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
+signed long long Float ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long Double ::toSInt(void) const { return static_cast<signed long long>(value); }
+signed long long Repr ::toSInt(void) const { return machineValue->toSInt(); }
+
+
+// unsigned integer cast
+unsigned long long Value ::toUInt(void) const { assert(0); return 0; }
+unsigned long long Null ::toUInt(void) const { return 0; }
+unsigned long long Bool ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long SInt ::toUInt(void) const { assert(value >= 0); return static_cast<signed long long>(value); }
+unsigned long long UInt ::toUInt(void) const { return value; }
+unsigned long long Float ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long Double ::toUInt(void) const { return static_cast<unsigned long long>(value); }
+unsigned long long Repr ::toUInt(void) const { return machineValue->toUInt(); }
+
+
+// floating point cast
+float Value ::toFloat(void) const { assert(0); return 0; }
+float Null ::toFloat(void) const { return 0; }
+float Bool ::toFloat(void) const { return static_cast<float>(value); }
+float SInt ::toFloat(void) const { return static_cast<float>(value); }
+float UInt ::toFloat(void) const { return static_cast<float>(value); }
+float Float ::toFloat(void) const { return value; }
+float Double ::toFloat(void) const { return value; }
+float Repr ::toFloat(void) const { return machineValue->toFloat(); }
+
+
+// floating point cast
+double Value ::toDouble(void) const { assert(0); return 0; }
+double Null ::toDouble(void) const { return 0; }
+double Bool ::toDouble(void) const { return static_cast<double>(value); }
+double SInt ::toDouble(void) const { return static_cast<double>(value); }
+double UInt ::toDouble(void) const { return static_cast<double>(value); }
+double Float ::toDouble(void) const { return value; }
+double Double ::toDouble(void) const { return value; }
+double Repr ::toDouble(void) const { return machineValue->toDouble(); }
+
+
+// pointer cast
+void * Value ::toPointer(void) const { assert(0); return NULL; }
+void * Null ::toPointer(void) const { return NULL; }
+void * Blob ::toPointer(void) const { return buf; }
+void * Pointer::toPointer(void) const { return (void *)value; }
+void * Repr ::toPointer(void) const { return machineValue->toPointer(); }
+
+void * Value ::toPointer(bool bind) { assert(0); return NULL; }
+void * Null ::toPointer(bool bind) { return NULL; }
+void * Blob ::toPointer(bool bind) { if (bind) bound = true; return buf; }
+void * Pointer::toPointer(bool bind) { return (void *)value; }
+void * Repr ::toPointer(bool bind) { return machineValue->toPointer(bind); }
+
+
+// unsigned int pointer cast
+unsigned long long Value ::toUIntPtr(void) const { assert(0); return 0; }
+unsigned long long Null ::toUIntPtr(void) const { return 0; }
+unsigned long long Pointer::toUIntPtr(void) const { return value; }
+unsigned long long Repr ::toUIntPtr(void) const { return machineValue->toUIntPtr(); }
+
+
+// string cast
+const char * Value ::toString(void) const { assert(0); return NULL; }
+const char * Null ::toString(void) const { return NULL; }
+const char * String::toString(void) const { return value; }
+const char * Repr ::toString(void) const { return machineValue->toString(); }
+
+
+// virtual Value::visit()
+void Null ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bool ::visit(Visitor &visitor) { visitor.visit(this); }
+void SInt ::visit(Visitor &visitor) { visitor.visit(this); }
+void UInt ::visit(Visitor &visitor) { visitor.visit(this); }
+void Float ::visit(Visitor &visitor) { visitor.visit(this); }
+void Double ::visit(Visitor &visitor) { visitor.visit(this); }
+void String ::visit(Visitor &visitor) { visitor.visit(this); }
+void WString::visit(Visitor &visitor) { visitor.visit(this); }
+void Enum ::visit(Visitor &visitor) { visitor.visit(this); }
+void Bitmask::visit(Visitor &visitor) { visitor.visit(this); }
+void Struct ::visit(Visitor &visitor) { visitor.visit(this); }
+void Array ::visit(Visitor &visitor) { visitor.visit(this); }
+void Blob ::visit(Visitor &visitor) { visitor.visit(this); }
+void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
+void Repr ::visit(Visitor &visitor) { visitor.visit(this); }
+
+
+void Visitor::visit(Null *) { assert(0); }
+void Visitor::visit(Bool *) { assert(0); }
+void Visitor::visit(SInt *) { assert(0); }
+void Visitor::visit(UInt *) { assert(0); }
+void Visitor::visit(Float *) { assert(0); }
+void Visitor::visit(Double *) { assert(0); }
+void Visitor::visit(String *) { assert(0); }
+void Visitor::visit(WString *) { assert(0); }
+void Visitor::visit(Enum *node) { assert(0); }
+void Visitor::visit(Bitmask *node) { visit(static_cast<UInt *>(node)); }
+void Visitor::visit(Struct *) { assert(0); }
+void Visitor::visit(Array *) { assert(0); }
+void Visitor::visit(Blob *) { assert(0); }
+void Visitor::visit(Pointer *) { assert(0); }
+void Visitor::visit(Repr *node) { node->machineValue->visit(*this); }
+
+
+Value &
+Value::operator[] (size_t index) const {
+ const Array *array = toArray();
+ if (array) {
+ if (index < array->values.size()) {
+ return *array->values[index];
+ }
+ }
+ return null;
+}
+
+} /* namespace trace */