diff options
Diffstat (limited to 'js/ipc/JavaScriptLogging.h')
-rw-r--r-- | js/ipc/JavaScriptLogging.h | 231 |
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 |