Bug 1034689 part 2 - Add AssignJSFlatString and use it. r=bz,terrence
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 12 Jul 2014 09:43:06 +0200
changeset 214533 046c577511ef8cc0cbf340ee7f63eccf41bb364a
parent 214532 7dd2566f434919179a0da180696e0abe66103874
child 214534 06fc258b16f8196a1fbb6c83f8af92d4a316eb1f
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, terrence
bugs1034689
milestone33.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 1034689 part 2 - Add AssignJSFlatString and use it. r=bz,terrence
dom/base/nsJSTimeoutHandler.cpp
dom/base/nsJSUtils.h
dom/bindings/BindingUtils.cpp
dom/bindings/Exceptions.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
js/src/jsfriendapi.h
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -344,18 +344,18 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
     // if CSP is enabled, and setTimeout/setInterval was called with a string,
     // disable the registration and log an error
     ErrorResult error;
     *aAllowEval = CheckCSPForEval(cx, aWindow, error);
     if (error.Failed() || !*aAllowEval) {
       return error.ErrorCode();
     }
 
-    mExpr.Append(JS_GetFlatStringChars(expr),
-                 JS_GetStringLength(JS_FORGET_STRING_FLATNESS(expr)));
+    MOZ_ASSERT(mExpr.IsEmpty());
+    AssignJSFlatString(mExpr, expr);
 
     // Get the calling location.
     const char *filename;
     if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
       mFileName.Assign(filename);
     }
   } else if (funobj) {
     *aAllowEval = true;
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -152,16 +152,28 @@ AssignJSString(JSContext *cx, T &dest, J
   if (MOZ_UNLIKELY(!js::CopyStringChars(cx, dest.BeginWriting(), s, len))) {
     return false;
   }
   dest.BeginWriting()[len] = '\0';
   dest.SetLength(len);
   return true;
 }
 
+inline void
+AssignJSFlatString(nsAString &dest, JSFlatString *s)
+{
+  size_t len = js::GetFlatStringLength(s);
+  static_assert(js::MaxStringLength < (1 << 28),
+                "Shouldn't overflow here or in SetCapacity");
+  dest.SetCapacity(len + 1);
+  js::CopyFlatStringChars(dest.BeginWriting(), s, len);
+  dest.BeginWriting()[len] = '\0';
+  dest.SetLength(len);
+}
+
 class nsAutoJSString : public nsAutoString
 {
 public:
 
   /**
    * nsAutoJSString should be default constructed, which leaves it empty
    * (this->IsEmpty()), and initialized with one of the init() methods below.
    */
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -81,20 +81,23 @@ ThrowInvalidThis(JSContext* aCx, const J
   // This should only be called for DOM methods/getters/setters, which
   // are JSNative-backed functions, so we can assume that
   // JS_ValueToFunction and JS_GetFunctionDisplayId will both return
   // non-null and that JS_GetStringCharsZ returns non-null.
   JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
   MOZ_ASSERT(func);
   JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
   MOZ_ASSERT(funcName);
+  nsAutoJSString funcNameStr;
+  if (!funcNameStr.init(aCx, funcName)) {
+    return false;
+  }
   JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
                          static_cast<const unsigned>(aErrorNumber),
-                         JS_GetStringCharsZ(aCx, funcName),
-                         ifaceName.get());
+                         funcNameStr.get(), ifaceName.get());
   return false;
 }
 
 bool
 ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
                  const ErrNum aErrorNumber,
                  prototypes::ID aProtoId)
 {
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -389,19 +389,17 @@ NS_IMETHODIMP JSStackFrame::GetFilename(
 }
 
 /* readonly attribute AString name; */
 NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
 {
   if (!mFunnameInitialized) {
     JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
     if (JSFlatString *name = desc.funDisplayName()) {
-      mFunname.Assign(JS_GetFlatStringChars(name),
-                      // XXXbz Can't JS_GetStringLength on JSFlatString!
-                      JS_GetStringLength(JS_FORGET_STRING_FLATNESS(name)));
+      AssignJSFlatString(mFunname, name);
     }
     mFunnameInitialized = true;
   }
 
   // The function name must be set to null if empty.
   if (mFunname.IsEmpty()) {
     aFunction.SetIsVoid(true);
   } else {
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1298,20 +1298,20 @@ NPUTF8*
   if (!id)
     return nullptr;
 
   if (!NPIdentifierIsString(id)) {
     return nullptr;
   }
 
   JSString *str = NPIdentifierToString(id);
-
-  return
-    ToNewUTF8String(nsDependentString(::JS_GetInternedStringChars(str),
-                                      ::JS_GetStringLength(str)));
+  nsAutoString autoStr;
+  AssignJSFlatString(autoStr, JS_ASSERT_STRING_IS_FLAT(str));
+
+  return ToNewUTF8String(autoStr);
 }
 
 int32_t
 _intfromidentifier(NPIdentifier id)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n"));
   }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -808,16 +808,22 @@ GetAtomLength(JSAtom *atom)
 static const uint32_t MaxStringLength = (1 << 28) - 1;
 
 MOZ_ALWAYS_INLINE size_t
 GetStringLength(JSString *s)
 {
     return reinterpret_cast<shadow::String*>(s)->length;
 }
 
+MOZ_ALWAYS_INLINE size_t
+GetFlatStringLength(JSFlatString *s)
+{
+    return reinterpret_cast<shadow::String*>(s)->length;
+}
+
 MOZ_ALWAYS_INLINE bool
 LinearStringHasLatin1Chars(JSLinearString *s)
 {
     return reinterpret_cast<shadow::String *>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
 }
 
 MOZ_ALWAYS_INLINE bool
 AtomHasLatin1Chars(JSAtom *atom)
@@ -856,16 +862,22 @@ GetTwoByteLinearStringChars(const JS::Au
 }
 
 MOZ_ALWAYS_INLINE JSLinearString *
 AtomToLinearString(JSAtom *atom)
 {
     return reinterpret_cast<JSLinearString *>(atom);
 }
 
+MOZ_ALWAYS_INLINE JSLinearString *
+FlatStringToLinearString(JSFlatString *s)
+{
+    return reinterpret_cast<JSLinearString *>(s);
+}
+
 MOZ_ALWAYS_INLINE const JS::Latin1Char *
 GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
 {
     return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom));
 }
 
 MOZ_ALWAYS_INLINE const jschar *
 GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
@@ -881,34 +893,45 @@ StringToLinearString(JSContext *cx, JSSt
 {
     using shadow::String;
     String *s = reinterpret_cast<String *>(str);
     if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
         return StringToLinearStringSlow(cx, str);
     return reinterpret_cast<JSLinearString *>(str);
 }
 
+MOZ_ALWAYS_INLINE void
+CopyLinearStringChars(jschar *dest, JSLinearString *s, size_t len)
+{
+    JS::AutoCheckCannotGC nogc;
+    if (LinearStringHasLatin1Chars(s)) {
+        const JS::Latin1Char *src = GetLatin1LinearStringChars(nogc, s);
+        for (size_t i = 0; i < len; i++)
+            dest[i] = src[i];
+    } else {
+        const jschar *src = GetTwoByteLinearStringChars(nogc, s);
+        mozilla::PodCopy(dest, src, len);
+    }
+}
+
 inline bool
 CopyStringChars(JSContext *cx, jschar *dest, JSString *s, size_t len)
 {
     JSLinearString *linear = StringToLinearString(cx, s);
     if (!linear)
         return false;
 
-    JS::AutoCheckCannotGC nogc;
-    if (LinearStringHasLatin1Chars(linear)) {
-        const JS::Latin1Char *src = GetLatin1LinearStringChars(nogc, linear);
-        for (size_t i = 0; i < len; i++)
-            dest[i] = src[i];
-    } else {
-        const jschar *src = GetTwoByteLinearStringChars(nogc, linear);
-        mozilla::PodCopy(dest, src, len);
-    }
+    CopyLinearStringChars(dest, linear, len);
+    return true;
+}
 
-    return true;
+inline void
+CopyFlatStringChars(jschar *dest, JSFlatString *s, size_t len)
+{
+    CopyLinearStringChars(dest, FlatStringToLinearString(s), len);
 }
 
 JS_FRIEND_API(bool)
 GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props);
 
 JS_FRIEND_API(bool)
 AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others);
 
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -61,16 +61,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "jsprf.h"
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
+#include "nsJSUtils.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "nsIException.h"
 #include "nsThreadUtils.h"
 #include "xpcpublic.h"
@@ -560,17 +561,20 @@ CycleCollectedJSRuntime::DescribeGCThing
 
     // Give the subclass a chance to do something
     if (DescribeCustomObjects(obj, clasp, name)) {
       // Nothing else to do!
     } else if (js::IsFunctionObject(obj)) {
       JSFunction* fun = JS_GetObjectFunction(obj);
       JSString* str = JS_GetFunctionDisplayId(fun);
       if (str) {
-        NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
+        JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(str);
+        nsAutoString chars;
+        AssignJSFlatString(chars, flat);
+        NS_ConvertUTF16toUTF8 fname(chars);
         JS_snprintf(name, sizeof(name),
                     "JS Object (Function - %s)", fname.get());
       } else {
         JS_snprintf(name, sizeof(name), "JS Object (Function)");
       }
     } else {
       JS_snprintf(name, sizeof(name), "JS Object (%s)",
                   clasp->name);