/* -*- 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 "js/Wrapper.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 void print(const char* fmt, const T1& a1) { nsAutoCString tmp1; format(a1, tmp1); print(nsPrintfCString(fmt, tmp1.get())); } template 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 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); obj = js::UncheckedUnwrap(obj, true); JSAutoRealm ar(cx, obj); objDesc = js::ObjectClassName(cx, obj); side = shared->isParent() ? "parent" : "child"; ptr = obj; } else { objDesc = ""; side = shared->isParent() ? "child" : "parent"; ptr = nullptr; } out = nsPrintfCString("<%s %s:%" PRIu64 ":%p>", side, objDesc, id.serialNumber(), ptr); } void format(const ReceiverObj& obj, nsCString& out) { formatObject(true, true, obj.id, out); } void format(const nsTArray& 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(""); } 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) { Maybe objId(ObjectId::deserialize(ovar.get_LocalObject().serializedId())); MOZ_RELEASE_ASSERT(objId.isSome()); formatObject(incoming, true, objId.value(), out); } else { Maybe objId(ObjectId::deserialize(ovar.get_RemoteObject().serializedId())); MOZ_RELEASE_ASSERT(objId.isSome()); formatObject(incoming, false, objId.value(), out); } break; } case JSVariant::TSymbolVariant: { out = ""; 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 = ""; break; } default: { out = ""; break; } } } void format(const Identifier& id, nsCString& out) { switch (id.variant.type()) { case JSIDVariant::TSymbolVariant: { out = ""; 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