Bug 1032726 part 3 - Make FindEnumStringIndex work with Latin1 strings. r=bz,terrence
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 02 Jul 2014 15:45:04 +0200
changeset 191907 219b6b2a4a29298988a0eeecb2eba9734c1917d4
parent 191906 60e70f9d98cbfab0ffd04576261b1193e02a0c1c
child 191908 df2d52a1ac2990799fd0758ed296b8840415262c
push id45687
push userjandemooij@gmail.com
push dateWed, 02 Jul 2014 13:51:46 +0000
treeherdermozilla-inbound@219b6b2a4a29 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, terrence
bugs1032726
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 1032726 part 3 - Make FindEnumStringIndex work with Latin1 strings. r=bz,terrence
dom/bindings/BindingUtils.h
js/src/jsapi.cpp
js/src/jsapi.h
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1051,84 +1051,112 @@ inline bool
 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
                                 T& value, JS::MutableHandle<JS::Value> rval)
 {
   return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
 }
 
 template<bool Fatal>
 inline bool
-EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
-                  const char* type, const char* sourceDescription)
+EnumValueNotFound(JSContext* cx, JSString* str, const char* type,
+                  const char* sourceDescription)
 {
   return false;
 }
 
 template<>
 inline bool
-EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
-                         const char* type, const char* sourceDescription)
+EnumValueNotFound<false>(JSContext* cx, JSString* str, const char* type,
+                         const char* sourceDescription)
 {
   // TODO: Log a warning to the console.
   return true;
 }
 
 template<>
 inline bool
-EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
-                        const char* type, const char* sourceDescription)
+EnumValueNotFound<true>(JSContext* cx, JSString* str, const char* type,
+                        const char* sourceDescription)
 {
-  NS_LossyConvertUTF16toASCII deflated(static_cast<const char16_t*>(chars),
-                                       length);
+  JSAutoByteString deflated(cx, str);
+  if (!deflated) {
+    return false;
+  }
   return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
-                           deflated.get(), type);
+                           deflated.ptr(), type);
 }
 
-
-template<bool InvalidValueFatal>
+template<typename CharT>
 inline int
-FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
-                    const char* type, const char* sourceDescription, bool* ok)
+FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
 {
-  // JS_StringEqualsAscii is slow as molasses, so don't use it here.
-  JSString* str = JS::ToString(cx, v);
-  if (!str) {
-    *ok = false;
-    return 0;
-  }
-  JS::Anchor<JSString*> anchor(str);
-  size_t length;
-  const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length);
-  if (!chars) {
-    *ok = false;
-    return 0;
-  }
   int i = 0;
   for (const EnumEntry* value = values; value->value; ++value, ++i) {
     if (length != value->length) {
       continue;
     }
 
     bool equal = true;
     const char* val = value->value;
     for (size_t j = 0; j != length; ++j) {
       if (unsigned(val[j]) != unsigned(chars[j])) {
         equal = false;
         break;
       }
     }
 
     if (equal) {
-      *ok = true;
       return i;
     }
   }
 
-  *ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
-                                             sourceDescription);
+  return -1;
+}
+
+template<bool InvalidValueFatal>
+inline int
+FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
+                    const char* type, const char* sourceDescription, bool* ok)
+{
+  // JS_StringEqualsAscii is slow as molasses, so don't use it here.
+  JSString* str = JS::ToString(cx, v);
+  if (!str) {
+    *ok = false;
+    return 0;
+  }
+  JS::Anchor<JSString*> anchor(str);
+
+  {
+    int index;
+    size_t length;
+    JS::AutoCheckCannotGC nogc;
+    if (JS_StringHasLatin1Chars(str)) {
+      const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
+                                                                     &length);
+      if (!chars) {
+        *ok = false;
+        return 0;
+      }
+      index = FindEnumStringIndexImpl(chars, length, values);
+    } else {
+      const jschar* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
+                                                              &length);
+      if (!chars) {
+        *ok = false;
+        return 0;
+      }
+      index = FindEnumStringIndexImpl(chars, length, values);
+    }
+    if (index >= 0) {
+      *ok = true;
+      return index;
+    }
+  }
+
+  *ok = EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
   return -1;
 }
 
 inline nsWrapperCache*
 GetWrapperCache(const ParentObject& aParentObject)
 {
   return aParentObject.mWrapperCache;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5360,16 +5360,31 @@ JS_GetStringCharsAndLength(JSContext *cx
     assertSameCompartment(cx, str);
     JSLinearString *linear = str->ensureLinear(cx);
     if (!linear)
         return nullptr;
     *plength = linear->length();
     return linear->chars();
 }
 
+JS_PUBLIC_API(const JS::Latin1Char *)
+JS_GetLatin1StringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
+                                 size_t *plength)
+{
+    JS_ASSERT(plength);
+    AssertHeapIsIdleOrStringIsFlat(cx, str);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, str);
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return nullptr;
+    *plength = linear->length();
+    return linear->latin1Chars(nogc);
+}
+
 JS_PUBLIC_API(const jschar *)
 JS_GetTwoByteStringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
                                   size_t *plength)
 {
     JS_ASSERT(plength);
     AssertHeapIsIdleOrStringIsFlat(cx, str);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, str);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4168,16 +4168,20 @@ JS_GetStringLength(JSString *str);
 
 /* Returns true iff the string's characters are stored as Latin1. */
 extern JS_PUBLIC_API(bool)
 JS_StringHasLatin1Chars(JSString *str);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *length);
 
+extern JS_PUBLIC_API(const JS::Latin1Char *)
+JS_GetLatin1StringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
+                                 size_t *length);
+
 extern JS_PUBLIC_API(const jschar *)
 JS_GetTwoByteStringCharsAndLength(JSContext *cx, const JS::AutoCheckCannotGC &nogc, JSString *str,
                                   size_t *length);
 
 extern JS_PUBLIC_API(const jschar *)
 JS_GetInternedStringChars(JSString *str);
 
 extern JS_PUBLIC_API(const jschar *)