Bug 995047. Change out stack/exception APIs to hand out AString instead of AUTF8String for filename/functionname, so we end up with fewer string conversions in practice. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 11 Apr 2014 22:20:40 -0400
changeset 178564 0071ce761fca90638278ca70b1d09a0f5ae09002
parent 178563 3d4f0e5e5ee0bae1dce31a861ce304c2e3fdd0bc
child 178565 4d621c19841e81c79a179ea8de054c6e039f544b
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewerssmaug
bugs995047
milestone31.0a1
Bug 995047. Change out stack/exception APIs to hand out AString instead of AUTF8String for filename/functionname, so we end up with fewer string conversions in practice. r=smaug
content/base/src/nsHostObjectProtocolHandler.cpp
dom/base/Console.cpp
dom/base/DOMException.cpp
dom/base/DOMException.h
dom/bindings/Exceptions.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
xpcom/base/nsIException.idl
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -89,23 +89,24 @@ class BlobURLsReporter MOZ_FINAL : publi
     nsAutoCString origin;
     nsCOMPtr<nsIURI> principalURI;
     if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI)))
         && principalURI) {
       principalURI->GetPrePath(origin);
     }
 
     for (uint32_t i = 0; i < maxFrames && frame; ++i) {
-      nsCString fileName;
+      nsString fileNameUTF16;
       int32_t lineNumber = 0;
 
-      frame->GetFilename(fileName);
+      frame->GetFilename(fileNameUTF16);
       frame->GetLineNumber(&lineNumber);
 
-      if (!fileName.IsEmpty()) {
+      if (!fileNameUTF16.IsEmpty()) {
+        NS_ConvertUTF16toUTF8 fileName(fileNameUTF16);
         stack += "js(";
         if (!origin.IsEmpty()) {
           // Make the file name root-relative for conciseness if possible.
           const char* originData;
           uint32_t originLen;
 
           originLen = origin.GetData(&originData);
           // If fileName starts with origin + "/", cut up to that "/".
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -809,42 +809,37 @@ Console::Method(JSContext* aCx, MethodNa
       Throw(aCx, rv);
       return;
     }
 
     if (language == nsIProgrammingLanguage::JAVASCRIPT ||
         language == nsIProgrammingLanguage::JAVASCRIPT2) {
       ConsoleStackEntry& data = *callData->mStack.AppendElement();
 
-      nsCString string;
-      rv = stack->GetFilename(string);
+      rv = stack->GetFilename(data.mFilename);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
-      CopyUTF8toUTF16(string, data.mFilename);
-
       int32_t lineNumber;
       rv = stack->GetLineNumber(&lineNumber);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
       data.mLineNumber = lineNumber;
 
-      rv = stack->GetName(string);
+      rv = stack->GetName(data.mFunctionName);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
-      CopyUTF8toUTF16(string, data.mFunctionName);
-
       data.mLanguage = language;
     }
 
     nsCOMPtr<nsIStackFrame> caller;
     rv = stack->GetCaller(getter_AddRefs(caller));
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return;
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -315,19 +315,19 @@ Exception::GetName(nsACString& aName)
     if (name) {
       aName.Assign(name);
     }
   }
 
   return NS_OK;
 }
 
-/* readonly attribute AUTF8String filename; */
+/* readonly attribute AString filename; */
 NS_IMETHODIMP
-Exception::GetFilename(nsACString& aFilename)
+Exception::GetFilename(nsAString& aFilename)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (mLocation) {
     return mLocation->GetFilename(aFilename);
   }
 
   aFilename.Assign(mFilename);
@@ -504,28 +504,16 @@ Exception::GetName(nsString& retval)
 #ifdef DEBUG
   DebugOnly<nsresult> rv =
 #endif
   GetName(str);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   CopyUTF8toUTF16(str, retval);
 }
 
-void
-Exception::GetFilename(nsString& retval)
-{
-  nsCString str;
-#ifdef DEBUG
-  DebugOnly<nsresult> rv =
-#endif
-  GetFilename(str);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  CopyUTF8toUTF16(str, retval);
-}
-
 uint32_t
 Exception::LineNumber() const
 {
   if (mLocation) {
     int32_t lineno;
     if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) {
       return lineno;
     }
@@ -617,25 +605,27 @@ DOMException::ToString(nsACString& aRetu
   static const char defaultLocation[] = "<unknown>";
   static const char defaultName[] = "<unknown>";
   static const char format[] =
     "[Exception... \"%s\"  code: \"%d\" nsresult: \"0x%x (%s)\"  location: \"%s\"]";
 
   nsAutoCString location;
 
   if (mInner) {
-    nsCString filename;
+    nsString filename;
     mInner->GetFilename(filename);
 
     if (!filename.IsEmpty()) {
       uint32_t line_nr = 0;
 
       mInner->GetLineNumber(&line_nr);
 
-      char *temp = PR_smprintf("%s Line: %d", filename.get(), line_nr);
+      char *temp = PR_smprintf("%s Line: %d",
+                               NS_ConvertUTF16toUTF8(filename).get(),
+                               line_nr);
       if (temp) {
         location.Assign(temp);
         PR_smprintf_free(temp);
       }
     }
   }
 
   if (location.IsEmpty()) {
--- a/dom/base/DOMException.h
+++ b/dom/base/DOMException.h
@@ -64,17 +64,17 @@ public:
   nsISupports* GetParentObject() const { return nullptr; }
 
   void GetMessageMoz(nsString& retval);
 
   uint32_t Result() const;
 
   void GetName(nsString& retval);
 
-  void GetFilename(nsString& retval);
+  // The XPCOM GetFilename does the right thing.
 
   uint32_t LineNumber() const;
 
   uint32_t ColumnNumber() const;
 
   already_AddRefed<nsIStackFrame> GetLocation() const;
 
   already_AddRefed<nsISupports> GetInner() const;
@@ -95,17 +95,17 @@ public:
 protected:
   virtual ~Exception();
 
   nsCString       mMessage;
   nsresult        mResult;
   nsCString       mName;
   nsCOMPtr<nsIStackFrame> mLocation;
   nsCOMPtr<nsISupports> mData;
-  nsCString       mFilename;
+  nsString        mFilename;
   int             mLineNumber;
   nsCOMPtr<nsIException> mInner;
   bool            mInitialized;
 
   bool mHoldingJSVal;
   JS::Heap<JS::Value> mThrownJSVal;
 
 private:
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -297,18 +297,18 @@ private:
   }
 
   int32_t GetLineno();
 
   nsRefPtr<StackDescriptionOwner> mStackDescription;
   nsCOMPtr<nsIStackFrame> mCaller;
 
   // Cached values
-  nsCString mFilename;
-  nsCString mFunname;
+  nsString mFilename;
+  nsString mFunname;
   int32_t mLineno;
   uint32_t mLanguage;
 
   size_t mIndex;
 
   bool mFilenameInitialized;
   bool mFunnameInitialized;
   bool mLinenoInitialized;
@@ -369,44 +369,46 @@ NS_IMETHODIMP JSStackFrame::GetLanguageN
     aLanguageName.AssignASCII(js);
   } else {
     aLanguageName.AssignASCII(cpp);
   }
 
   return NS_OK;
 }
 
-/* readonly attribute string filename; */
-NS_IMETHODIMP JSStackFrame::GetFilename(nsACString& aFilename)
+/* readonly attribute AString filename; */
+NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
 {
   if (!mFilenameInitialized) {
     JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
     if (const char *filename = desc.filename()) {
-      mFilename.Assign(filename);
+      CopyUTF8toUTF16(filename, mFilename);
     }
     mFilenameInitialized = true;
   }
 
   // The filename must be set to null if empty.
   if (mFilename.IsEmpty()) {
     aFilename.SetIsVoid(true);
   } else {
     aFilename.Assign(mFilename);
   }
 
   return NS_OK;
 }
 
-/* readonly attribute string name; */
-NS_IMETHODIMP JSStackFrame::GetName(nsACString& aFunction)
+/* readonly attribute AString name; */
+NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
 {
   if (!mFunnameInitialized) {
     JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
     if (JSFlatString *name = desc.funDisplayName()) {
-      CopyUTF16toUTF8(JS_GetFlatStringChars(name), mFunname);
+      mFunname.Assign(JS_GetFlatStringChars(name),
+                      // XXXbz Can't JS_GetStringLength on JSFlatString!
+                      JS_GetStringLength(JS_FORGET_STRING_FLATNESS(name)));
     }
     mFunnameInitialized = true;
   }
 
   // The function name must be set to null if empty.
   if (mFunname.IsEmpty()) {
     aFunction.SetIsVoid(true);
   } else {
@@ -455,34 +457,36 @@ NS_IMETHODIMP JSStackFrame::GetCaller(ns
 
 /* AUTF8String toString (); */
 NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval)
 {
   _retval.Truncate();
 
   const char* frametype = IsJSFrame() ? "JS" : "native";
 
-  nsCString filename;
+  nsString filename;
   nsresult rv = GetFilename(filename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (filename.IsEmpty()) {
-    filename.AssignASCII("<unknown filename>");
+    filename.AssignLiteral("<unknown filename>");
   }
 
-  nsCString funname;
+  nsString funname;
   rv = GetName(funname);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (funname.IsEmpty()) {
-    funname.AssignASCII("<TOP_LEVEL>");
+    funname.AssignLiteral("<TOP_LEVEL>");
   }
   static const char format[] = "%s frame :: %s :: %s :: line %d";
-  _retval.AppendPrintf(format, frametype, filename.get(),
-                       funname.get(), GetLineno());
+  _retval.AppendPrintf(format, frametype,
+                       NS_ConvertUTF16toUTF8(filename).get(),
+                       NS_ConvertUTF16toUTF8(funname).get(),
+                       GetLineno());
   return NS_OK;
 }
 
 /* static */ already_AddRefed<nsIStackFrame>
 JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
 {
   static const unsigned MAX_FRAMES = 100;
   if (aMaxDepth < 0) {
@@ -506,18 +510,18 @@ JSStackFrame::CreateStackFrameLocation(u
                                        const char* aFunctionName,
                                        int32_t aLineNumber,
                                        nsIStackFrame* aCaller)
 {
   nsRefPtr<JSStackFrame> self = new JSStackFrame(nullptr, 0);
 
   self->mLanguage = aLanguage;
   self->mLineno = aLineNumber;
-  self->mFilename = aFilename;
-  self->mFunname = aFunctionName;
+  CopyUTF8toUTF16(aFilename, self->mFilename);
+  CopyUTF8toUTF16(aFunctionName, self->mFunname);
 
   self->mCaller = aCaller;
 
   return self.forget();
 }
 
 already_AddRefed<nsIStackFrame>
 CreateStack(JSContext* aCx, int32_t aMaxDepth)
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -1536,23 +1536,23 @@ AssembleSandboxMemoryReporterName(JSCont
     NS_ENSURE_TRUE(cc, NS_ERROR_INVALID_ARG);
 
     // Get the current source info from xpc.
     nsCOMPtr<nsIStackFrame> frame;
     xpc->GetCurrentJSStack(getter_AddRefs(frame));
 
     // Append the caller's location information.
     if (frame) {
-        nsCString location;
+        nsString location;
         int32_t lineNumber = 0;
         frame->GetFilename(location);
         frame->GetLineNumber(&lineNumber);
 
         sandboxName.AppendLiteral(" (from: ");
-        sandboxName.Append(location);
+        sandboxName.Append(NS_ConvertUTF16toUTF8(location));
         sandboxName.AppendLiteral(":");
         sandboxName.AppendInt(lineNumber);
         sandboxName.AppendLiteral(")");
     }
 
     return NS_OK;
 }
 
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2594,30 +2594,30 @@ nsXPCComponents_Utils::ReportError(Handl
     RootedString msgstr(cx, ToString(cx, error));
     if (!msgstr)
         return NS_OK;
 
     nsCOMPtr<nsIStackFrame> frame;
     nsXPConnect *xpc = nsXPConnect::XPConnect();
     xpc->GetCurrentJSStack(getter_AddRefs(frame));
 
-    nsCString fileName;
+    nsString fileName;
     int32_t lineNo = 0;
     if (frame) {
         frame->GetFilename(fileName);
         frame->GetLineNumber(&lineNo);
     }
 
     const jschar *msgchars = JS_GetStringCharsZ(cx, msgstr);
     if (!msgchars)
         return NS_OK;
 
     nsresult rv = scripterr->InitWithWindowID(
             nsDependentString(static_cast<const char16_t *>(msgchars)),
-            NS_ConvertUTF8toUTF16(fileName), EmptyString(), lineNo, 0, 0,
+            fileName, EmptyString(), lineNo, 0, 0,
             "XPConnect JavaScript", innerWindowID);
     NS_ENSURE_SUCCESS(rv, NS_OK);
 
     console->LogMessage(scripterr);
     return NS_OK;
 }
 
 /* void evalInSandbox(in AString source, in nativeobj sandbox); */
@@ -2667,17 +2667,19 @@ nsXPCComponents_Utils::EvalInSandbox(con
         // Get the current source info from xpc.
         nsresult rv;
         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
         NS_ENSURE_SUCCESS(rv, rv);
 
         nsCOMPtr<nsIStackFrame> frame;
         xpc->GetCurrentJSStack(getter_AddRefs(frame));
         if (frame) {
-            frame->GetFilename(filename);
+            nsString frameFile;
+            frame->GetFilename(frameFile);
+            CopyUTF16toUTF8(frameFile, filename);
             frame->GetLineNumber(&lineNo);
         }
     }
 
     return xpc::EvalInSandbox(cx, sandbox, source, filename, lineNo,
                               jsVersion, false, retval);
 }
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -907,31 +907,31 @@ nsXPCWrappedJSClass::CheckForException(X
                         scriptError = do_CreateInstance(XPC_SCRIPT_ERROR_CONTRACTID);
                         if (nullptr != scriptError) {
                             nsCString newMessage;
                             rv = xpc_exception->ToString(newMessage);
                             if (NS_SUCCEEDED(rv)) {
                                 // try to get filename, lineno from the first
                                 // stack frame location.
                                 int32_t lineNumber = 0;
-                                nsCString sourceName;
+                                nsString sourceName;
 
                                 nsCOMPtr<nsIStackFrame> location;
                                 xpc_exception->
                                     GetLocation(getter_AddRefs(location));
                                 if (location) {
                                     // Get line number w/o checking; 0 is ok.
                                     location->GetLineNumber(&lineNumber);
 
                                     // get a filename.
                                     rv = location->GetFilename(sourceName);
                                 }
 
                                 rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(newMessage),
-                                                                   NS_ConvertUTF8toUTF16(sourceName),
+                                                                   sourceName,
                                                                    EmptyString(),
                                                                    lineNumber, 0, 0,
                                                                    "XPConnect JavaScript",
                                                                    nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
                                 if (NS_FAILED(rv))
                                     scriptError = nullptr;
                             }
                         }
--- a/xpcom/base/nsIException.idl
+++ b/xpcom/base/nsIException.idl
@@ -5,33 +5,33 @@
 
 /*
  * Interfaces for representing cross-language exceptions and stack traces.
  */
 
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(60abee59-717e-477d-8bbb-a1c3e7067126)]
+[scriptable, uuid(3bc4793f-e6be-44d6-b839-d6b9e85e5346)]
 interface nsIStackFrame : nsISupports
 {
     // see nsIProgrammingLanguage for list of language consts
     readonly attribute uint32_t                language;
     readonly attribute AUTF8String             languageName;
-    readonly attribute AUTF8String             filename;
-    readonly attribute AUTF8String             name;
+    readonly attribute AString                 filename;
+    readonly attribute AString                 name;
     // Valid line numbers begin at '1'. '0' indicates unknown.
     readonly attribute int32_t                 lineNumber;
     readonly attribute AUTF8String             sourceLine;
     readonly attribute nsIStackFrame           caller;
 
     AUTF8String toString();
 };
 
-[scriptable, uuid(6738090a-ba6f-4f3f-8aa0-b9f6311262a5)]
+[scriptable, uuid(1caf1461-be1d-4b79-a552-5292b6bf3c35)]
 interface nsIException : nsISupports
 {
     // A custom message set by the thrower.
     [binaryname(MessageMoz)] readonly attribute AUTF8String message;
     // The nsresult associated with this exception.
     readonly attribute nsresult                result;
     // The name of the error code (ie, a string repr of |result|)
     readonly attribute AUTF8String             name;
@@ -39,17 +39,17 @@ interface nsIException : nsISupports
     // Filename location.  This is the location that caused the
     // error, which may or may not be a source file location.
     // For example, standard language errors would generally have
     // the same location as their top stack entry.  File
     // parsers may put the location of the file they were parsing,
     // etc.
 
     // null indicates "no data"
-    readonly attribute AUTF8String             filename;
+    readonly attribute AString                 filename;
     // Valid line numbers begin at '1'. '0' indicates unknown.
     readonly attribute uint32_t                lineNumber;
     // Valid column numbers begin at 0. 
     // We don't have an unambiguous indicator for unknown.
     readonly attribute uint32_t                columnNumber;
 
     // A stack trace, if available.
     readonly attribute nsIStackFrame           location;