Raw File
JavaScriptLogging.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sw=2 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 <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);
      obj = js::UncheckedUnwrap(obj, true);

      JSAutoRealm ar(cx, obj);
      objDesc = js::ObjectClassName(cx, obj);
      side = shared->isParent() ? "parent" : "child";
      ptr = obj;
    } else {
      objDesc = "<cpow>";
      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<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) {
          Maybe<ObjectId> objId(
              ObjectId::deserialize(ovar.get_LocalObject().serializedId()));
          MOZ_RELEASE_ASSERT(objId.isSome());
          formatObject(incoming, true, objId.value(), out);
        } else {
          Maybe<ObjectId> objId(
              ObjectId::deserialize(ovar.get_RemoteObject().serializedId()));
          MOZ_RELEASE_ASSERT(objId.isSome());
          formatObject(incoming, false, objId.value(), 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
back to top