summaryrefslogtreecommitdiffstats
path: root/js/ipc/JavaScriptLogging.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/ipc/JavaScriptLogging.h')
-rw-r--r--js/ipc/JavaScriptLogging.h231
1 files changed, 231 insertions, 0 deletions
diff --git a/js/ipc/JavaScriptLogging.h b/js/ipc/JavaScriptLogging.h
new file mode 100644
index 000000000..187579a4b
--- /dev/null
+++ b/js/ipc/JavaScriptLogging.h
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_jsipc_JavaScriptLogging__
+#define mozilla_jsipc_JavaScriptLogging__
+
+#include "nsString.h"
+#include "nsPrintfCString.h"
+#include "jsfriendapi.h"
+#include "jswrapper.h"
+
+namespace mozilla {
+namespace jsipc {
+
+#define LOG(...) \
+ PR_BEGIN_MACRO \
+ if (LoggingEnabled()) { \
+ Logging log(this, cx); \
+ log.print(__VA_ARGS__); \
+ } \
+ PR_END_MACRO
+
+#define LOG_STACK() \
+ PR_BEGIN_MACRO \
+ if (StackLoggingEnabled()) { \
+ js::DumpBacktrace(cx); \
+ } \
+ PR_END_MACRO
+
+struct ReceiverObj
+{
+ ObjectId id;
+ explicit ReceiverObj(ObjectId id) : id(id) {}
+};
+
+struct InVariant
+{
+ JSVariant variant;
+ explicit InVariant(const JSVariant& variant) : variant(variant) {}
+};
+
+struct OutVariant
+{
+ JSVariant variant;
+ explicit OutVariant(const JSVariant& variant) : variant(variant) {}
+};
+
+struct Identifier
+{
+ JSIDVariant variant;
+ explicit Identifier(const JSIDVariant& variant) : variant(variant) {}
+};
+
+class Logging
+{
+ public:
+ Logging(JavaScriptShared* shared, JSContext* cx) : shared(shared), cx(cx) {}
+
+ void print(const nsCString& str) {
+ const char* side = shared->isParent() ? "from child" : "from parent";
+ printf("CPOW %s: %s\n", side, str.get());
+ }
+
+ void print(const char* str) {
+ print(nsCString(str));
+ }
+ template<typename T1>
+ void print(const char* fmt, const T1& a1) {
+ nsAutoCString tmp1;
+ format(a1, tmp1);
+ print(nsPrintfCString(fmt, tmp1.get()));
+ }
+ template<typename T1, typename T2>
+ void print(const char* fmt, const T1& a1, const T2& a2) {
+ nsAutoCString tmp1;
+ nsAutoCString tmp2;
+ format(a1, tmp1);
+ format(a2, tmp2);
+ print(nsPrintfCString(fmt, tmp1.get(), tmp2.get()));
+ }
+ template<typename T1, typename T2, typename T3>
+ void print(const char* fmt, const T1& a1, const T2& a2, const T3& a3) {
+ nsAutoCString tmp1;
+ nsAutoCString tmp2;
+ nsAutoCString tmp3;
+ format(a1, tmp1);
+ format(a2, tmp2);
+ format(a3, tmp3);
+ print(nsPrintfCString(fmt, tmp1.get(), tmp2.get(), tmp3.get()));
+ }
+
+ void format(const nsString& str, nsCString& out) {
+ out = NS_ConvertUTF16toUTF8(str);
+ }
+
+ void formatObject(bool incoming, bool local, ObjectId id, nsCString& out) {
+ const char* side;
+ const char* objDesc;
+ void* ptr;
+
+ if (local == incoming) {
+ JS::RootedObject obj(cx);
+ obj = shared->objects_.find(id);
+ if (obj) {
+ JSAutoCompartment ac(cx, obj);
+ objDesc = js::ObjectClassName(cx, obj);
+ } else {
+ objDesc = "<dead object>";
+ }
+
+ side = shared->isParent() ? "parent" : "child";
+ ptr = js::UncheckedUnwrap(obj, true);
+ } else {
+ objDesc = "<cpow>";
+ side = shared->isParent() ? "child" : "parent";
+ ptr = nullptr;
+ }
+
+ out = nsPrintfCString("<%s %s:%d:%p>", side, objDesc, id.serialNumber(), ptr);
+ }
+
+ void format(const ReceiverObj& obj, nsCString& out) {
+ formatObject(true, true, obj.id, out);
+ }
+
+ void format(const nsTArray<JSParam>& values, nsCString& out) {
+ nsAutoCString tmp;
+ out.Truncate();
+ for (size_t i = 0; i < values.Length(); i++) {
+ if (i)
+ out.AppendLiteral(", ");
+ if (values[i].type() == JSParam::Tvoid_t) {
+ out.AppendLiteral("<void>");
+ } else {
+ format(InVariant(values[i].get_JSVariant()), tmp);
+ out += tmp;
+ }
+ }
+ }
+
+ void format(const InVariant& value, nsCString& out) {
+ format(true, value.variant, out);
+ }
+
+ void format(const OutVariant& value, nsCString& out) {
+ format(false, value.variant, out);
+ }
+
+ void format(bool incoming, const JSVariant& value, nsCString& out) {
+ switch (value.type()) {
+ case JSVariant::TUndefinedVariant: {
+ out = "undefined";
+ break;
+ }
+ case JSVariant::TNullVariant: {
+ out = "null";
+ break;
+ }
+ case JSVariant::TnsString: {
+ nsAutoCString tmp;
+ format(value.get_nsString(), tmp);
+ out = nsPrintfCString("\"%s\"", tmp.get());
+ break;
+ }
+ case JSVariant::TObjectVariant: {
+ const ObjectVariant& ovar = value.get_ObjectVariant();
+ if (ovar.type() == ObjectVariant::TLocalObject)
+ formatObject(incoming, true, ObjectId::deserialize(ovar.get_LocalObject().serializedId()), out);
+ else
+ formatObject(incoming, false, ObjectId::deserialize(ovar.get_RemoteObject().serializedId()), out);
+ break;
+ }
+ case JSVariant::TSymbolVariant: {
+ out = "<Symbol>";
+ break;
+ }
+ case JSVariant::Tdouble: {
+ out = nsPrintfCString("%.0f", value.get_double());
+ break;
+ }
+ case JSVariant::Tbool: {
+ out = value.get_bool() ? "true" : "false";
+ break;
+ }
+ case JSVariant::TJSIID: {
+ out = "<JSIID>";
+ break;
+ }
+ default: {
+ out = "<JSIID>";
+ break;
+ }
+ }
+ }
+
+ void format(const Identifier& id, nsCString& out) {
+ switch (id.variant.type()) {
+ case JSIDVariant::TSymbolVariant: {
+ out = "<Symbol>";
+ break;
+ }
+ case JSIDVariant::TnsString: {
+ nsAutoCString tmp;
+ format(id.variant.get_nsString(), tmp);
+ out = nsPrintfCString("\"%s\"", tmp.get());
+ break;
+ }
+ case JSIDVariant::Tint32_t: {
+ out = nsPrintfCString("%d", id.variant.get_int32_t());
+ break;
+ }
+ default: {
+ out = "Unknown";
+ break;
+ }
+ }
+ }
+
+ private:
+ JavaScriptShared* shared;
+ JSContext* cx;
+};
+
+} // namespace jsipc
+} // namespace mozilla
+
+#endif