Bug 969762 - Support non-ASCII dump() messages on Windows. r=jimm
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Tue, 11 Feb 2014 05:50:16 +0900
changeset 167923 d7d447cac91b0cfa066864b1e63bc5c98f642dc3
parent 167922 9b2e849f5854ee03805194c2263e7ec3d5fb8d5d
child 167924 a00e2b91ded179554c56fb6d90f53bc703e61111
push id39594
push userVYV03354@nifty.ne.jp
push dateMon, 10 Feb 2014 20:50:43 +0000
treeherdermozilla-inbound@d7d447cac91b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs969762
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 969762 - Support non-ASCII dump() messages on Windows. r=jimm
content/base/src/nsFrameMessageManager.cpp
dom/base/nsGlobalWindow.cpp
dom/workers/WorkerScope.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/XPCShellImpl.cpp
xpcom/base/Debug.cpp
xpcom/base/Debug.h
xpcom/base/nsConsoleService.cpp
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -24,27 +24,25 @@
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMClassInfo.h"
 #include "nsIDOMFile.h"
 #include "xpcpublic.h"
+#include "mozilla/Debug.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
 #include "JavaScriptChild.h"
 #include "JavaScriptParent.h"
 #include "nsDOMLists.h"
 #include "nsPrintfCString.h"
 #include <algorithm>
 
-#ifdef ANDROID
-#include <android/log.h>
-#endif
 #ifdef XP_WIN
 #include <windows.h>
 # if defined(SendMessage)
 #  undef SendMessage
 # endif
 #endif
 
 using namespace mozilla;
@@ -718,26 +716,17 @@ nsFrameMessageManager::GetChildAt(uint32
 }
 
 
 // nsIContentFrameMessageManager
 
 NS_IMETHODIMP
 nsFrameMessageManager::Dump(const nsAString& aStr)
 {
-#ifdef ANDROID
-  __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
-#endif
-#ifdef XP_WIN
-  if (IsDebuggerPresent()) {
-    OutputDebugStringW(PromiseFlatString(aStr).get());
-  }
-#endif
-  fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
-  fflush(stdout);
+  PrintToDebugger(aStr, stdout);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::PrivateNoteIntentionalCrash()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -227,20 +227,16 @@
 
 // Apple system headers seem to have a check() macro.  <sigh>
 #ifdef check
 class nsIScriptTimeoutHandler;
 #undef check
 #endif // check
 #include "AccessCheck.h"
 
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDOMLeakPRLog;
 #endif
 
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
 #else
@@ -5807,41 +5803,17 @@ nsGlobalWindow::GetFullScreen(bool* aFul
 
 NS_IMETHODIMP
 nsGlobalWindow::Dump(const nsAString& aStr)
 {
   if (!nsContentUtils::DOMWindowDumpEnabled()) {
     return NS_OK;
   }
 
-  char *cstr = ToNewUTF8String(aStr);
-
-#if defined(XP_MACOSX)
-  // have to convert \r to \n so that printing to the console works
-  char *c = cstr, *cEnd = cstr + strlen(cstr);
-  while (c < cEnd) {
-    if (*c == '\r')
-      *c = '\n';
-    c++;
-  }
-#endif
-
-  if (cstr) {
-#ifdef XP_WIN
-    PrintToDebugger(cstr);
-#endif
-#ifdef ANDROID
-    __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
-#endif
-    FILE *fp = gDumpFile ? gDumpFile : stdout;
-    fputs(cstr, fp);
-    fflush(fp);
-    nsMemory::Free(cstr);
-  }
-
+  PrintToDebugger(aStr, gDumpFile ? gDumpFile : stdout);
   return NS_OK;
 }
 
 void
 nsGlobalWindow::EnsureReflowFlushAndPaint()
 {
   MOZ_ASSERT(IsOuterWindow());
   NS_ASSERTION(mDocShell, "EnsureReflowFlushAndPaint() called with no "
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -2,24 +2,21 @@
 /* vim: set ts=2 et sw=2 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/. */
 
 #include "WorkerScope.h"
 
 #include "jsapi.h"
+#include "mozilla/Debug.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
 
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-
 #include "Console.h"
 #include "Location.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "WorkerPrivate.h"
 
@@ -256,23 +253,18 @@ WorkerGlobalScope::Dump(const Optional<n
   if (!aString.WasPassed()) {
     return;
   }
 
   if (!mWorkerPrivate->DumpEnabled()) {
     return;
   }
 
-  NS_ConvertUTF16toUTF8 str(aString.Value());
-
-#ifdef ANDROID
-  __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
-#endif
-  fputs(str.get(), stdout);
-  fflush(stdout);
+  PrintToDebugger(aString.Value(), stdout, kPrintToStream
+                                           | kPrintInfoLog);
 }
 
 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
 : WorkerGlobalScope(aWorkerPrivate)
 {
 }
 
 /* static */ bool
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -8,27 +8,22 @@
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #endif
 
 #include <cstdarg>
 
 #include "prlog.h"
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-#ifdef XP_WIN
-#include <windows.h>
-#endif
 
 #include "jsapi.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIComponentManager.h"
+#include "mozilla/Debug.h"
 #include "mozilla/Module.h"
 #include "nsIFile.h"
 #include "mozJSComponentLoader.h"
 #include "mozJSLoaderUtils.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIXPConnect.h"
 #include "nsIObserverService.h"
 #include "nsIScriptSecurityManager.h"
@@ -116,28 +111,19 @@ Dump(JSContext *cx, unsigned argc, Value
     if (!str)
         return false;
 
     size_t length;
     const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
     if (!chars)
         return false;
 
-    NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
-                                  length);
-#ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
-#endif
-#ifdef XP_WIN
-    if (IsDebuggerPresent()) {
-      OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
-    }
-#endif
-    fputs(utf8str.get(), stdout);
-    fflush(stdout);
+    nsDependentSubstring ustr(reinterpret_cast<const char16_t*>(chars),
+                              length);
+    PrintToDebugger(ustr, stdout);
     return true;
 }
 
 static bool
 Debug(JSContext *cx, unsigned argc, jsval *vp)
 {
 #ifdef DEBUG
     return Dump(cx, argc, vp);
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -3,16 +3,17 @@
  * 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/. */
 
 #include "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsprf.h"
 #include "js/OldDebugAPI.h"
+#include "mozilla/Debug.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIServiceManager.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #include "nsIDirectoryService.h"
@@ -27,20 +28,16 @@
 #include "nsAutoPtr.h"
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #include "BackstagePass.h"
 #include "nsCxPusher.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIPrincipal.h"
 
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 // all this crap is needed to do the interactive shell stuff
 #include <stdlib.h>
 #include <errno.h>
 #ifdef HAVE_IO_H
@@ -295,28 +292,19 @@ Dump(JSContext *cx, unsigned argc, jsval
     if (!str)
         return false;
 
     size_t length;
     const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
     if (!chars)
         return false;
 
-    NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
-                                  length);
-#ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
-#endif
-#ifdef XP_WIN
-    if (IsDebuggerPresent()) {
-      OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
-    }
-#endif
-    fputs(utf8str.get(), gOutFile);
-    fflush(gOutFile);
+    nsDependentSubstring ustr(reinterpret_cast<const char16_t*>(chars),
+                              length);
+    PrintToDebugger(ustr, gOutFile);
     return true;
 }
 
 static bool
 Load(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
--- a/xpcom/base/Debug.cpp
+++ b/xpcom/base/Debug.cpp
@@ -1,21 +1,66 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "mozilla/Debug.h"
 
 #ifdef XP_WIN
+#include <io.h>
 #include <windows.h>
 #endif
 
-#ifdef XP_WIN
+#ifdef ANDROID
+#include <android/log.h>
+#endif
 
-void mozilla::PrintToDebugger(const char* aStr)
+void mozilla::PrintToDebugger(const nsAString& aStr, FILE* aStream,
+                              LogOptions aOptions)
 {
-  if (::IsDebuggerPresent()) {
-    ::OutputDebugStringA(aStr);
+  nsString msg(aStr);
+  if (aOptions & kPrintNewLine) {
+    msg.AppendLiteral("\n");
+  }
+
+#ifdef XP_WIN
+  if ((aOptions & kPrintToDebugger) && ::IsDebuggerPresent()) {
+    ::OutputDebugStringW(msg.get());
+  }
+
+  if (!(aOptions & kPrintToStream)) {
+    return;
+  }
+
+  int fd = _fileno(aStream);
+  if (_isatty(fd)) {
+    fflush(aStream);
+    DWORD writtenCount;
+    WriteConsoleW(reinterpret_cast<HANDLE>(_get_osfhandle(fd)),
+                  msg.BeginReading(), msg.Length(),
+                  &writtenCount, nullptr);
+    return;
   }
-}
+#endif
+  NS_ConvertUTF16toUTF8 cstr(msg);
+#ifdef ANDROID
+  if (aOptions & (kPrintInfoLog | kPrintErrorLog)) {
+    __android_log_write(aOptions & kPrintErrorLog ? ANDROID_LOG_ERROR
+                                                  : ANDROID_LOG_INFO,
+                        "GeckoDump", cstr.get());
+  }
+#endif
 
+#ifndef XP_WIN
+  if (!(aOptions & kPrintToStream)) {
+    return;
+  }
 #endif
+
+#if defined(XP_MACOSX)
+  // have to convert \r to \n so that printing to the console works
+  cstr.ReplaceChar('\r', '\n');
+#endif
+
+  fputs(cstr.get(), aStream);
+  fflush(aStream);
+}
--- a/xpcom/base/Debug.h
+++ b/xpcom/base/Debug.h
@@ -1,20 +1,42 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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_Debug_h__
-#define mozilla_Debug_h__
+#ifndef mozilla_Debug_h
+#define mozilla_Debug_h
+
+#include "nsString.h"
+#include <stdio.h>
 
 namespace mozilla {
 
-#ifdef XP_WIN
+typedef uint32_t LogOptions;
+
+// Print a message to the specified stream.
+const LogOptions kPrintToStream   = 1 << 0;
+
+// Print a message to a debugger if the debugger is attached.
+// At the moment, only meaningful on Windows.
+const LogOptions kPrintToDebugger = 1 << 1;
+
+// Print an info-level message to the log.
+// At the moment, only meaningful on Andriod.
+const LogOptions kPrintInfoLog    = 1 << 2;
+
+// Print an error-level message to the log.
+// At the moment, only meaningful on Andriod.
+const LogOptions kPrintErrorLog   = 1 << 3;
+
+// Print a new line after the message.
+const LogOptions kPrintNewLine    = 1 << 4;
 
 // Print aStr to a debugger if the debugger is attached.
-void PrintToDebugger(const char* aStr);
-
-#endif
+void PrintToDebugger(const nsAString& aStr, FILE* aStream,
+                     LogOptions aOptions = kPrintToStream
+                                         | kPrintToDebugger
+                                         | kPrintInfoLog);
 
 } // namespace mozilla
 
-#endif // mozilla_Debug_h__
+#endif // mozilla_Debug_h
--- a/xpcom/base/nsConsoleService.cpp
+++ b/xpcom/base/nsConsoleService.cpp
@@ -15,25 +15,19 @@
 #include "nsThreadUtils.h"
 
 #include "nsConsoleService.h"
 #include "nsConsoleMessage.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIConsoleListener.h"
 #include "nsPrintfCString.h"
 
+#include "mozilla/Debug.h"
 #include "mozilla/Preferences.h"
 
-#if defined(ANDROID)
-#include <android/log.h>
-#endif
-#ifdef XP_WIN
-#include <windows.h>
-#endif
-
 using namespace mozilla;
 
 NS_IMPL_ADDREF(nsConsoleService)
 NS_IMPL_RELEASE(nsConsoleService)
 NS_IMPL_CLASSINFO(nsConsoleService, nullptr, nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON, NS_CONSOLESERVICE_CID)
 NS_IMPL_QUERY_INTERFACE1_CI(nsConsoleService, nsIConsoleService)
 NS_IMPL_CI_INTERFACE_GETTER1(nsConsoleService, nsIConsoleService)
 
@@ -186,34 +180,23 @@ nsConsoleService::LogMessageWithMode(nsI
 
     /*
      * Lock while updating buffer, and while taking snapshot of
      * listeners array.
      */
     {
         MutexAutoLock lock(mLock);
 
-#if defined(ANDROID)
-        if (outputMode == OutputToLog)
-        {
-            nsXPIDLString msg;
-            message->GetMessageMoz(getter_Copies(msg));
-            __android_log_print(ANDROID_LOG_ERROR, "GeckoConsole",
-                        "%s",
-                        NS_LossyConvertUTF16toASCII(msg).get());
+        nsString msg;
+        message->GetMessageMoz(getter_Copies(msg));
+        LogOptions options = kPrintToDebugger | kPrintNewLine;
+        if (outputMode == OutputToLog) {
+            options |= kPrintErrorLog;
         }
-#endif
-#ifdef XP_WIN
-        if (IsDebuggerPresent()) {
-            nsString msg;
-            message->GetMessageMoz(getter_Copies(msg));
-            msg.AppendLiteral("\n");
-            OutputDebugStringW(msg.get());
-        }
-#endif
+        PrintToDebugger(msg, nullptr, options);
 
         /*
          * If there's already a message in the slot we're about to replace,
          * we've wrapped around, and we need to release the old message.  We
          * save a pointer to it, so we can release below outside the lock.
          */
         retiredMessage = mMessages[mCurrent];