Bug 1542736 - Part 4: Replace JS_UNDEC with js::AsciiDigitToNumber. r=jwalden
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 11 Apr 2019 11:35:06 +0000
changeset 469055 544ee6df501b898955b11055eedeca824ca2605d
parent 469054 ae1ac8554873f1e9b4a574a5110aedb19f99c0c3
child 469056 21497aef0046d257fbaeec2e88e9e625b2d55c01
push id35856
push usercsabou@mozilla.com
push dateFri, 12 Apr 2019 03:19:48 +0000
treeherdermozilla-central@940684cd1065 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1542736
milestone68.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 1542736 - Part 4: Replace JS_UNDEC with js::AsciiDigitToNumber. r=jwalden js::AsciiDigitToNumber is an optimised version of mozilla::AsciiAlphanumericToNumber for known ASCII digit-only cases, which avoids the extra comparisons for ASCII alphabetical characters. This ensures replacing JS_UNDEC with js::AsciiDigitToNumber still emits the same assembly. Differential Revision: https://phabricator.services.mozilla.com/D26507
js/src/builtin/Array.cpp
js/src/builtin/RegExp.cpp
js/src/util/Text.h
js/src/vm/JSContext.cpp
js/src/vm/StringType.cpp
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -222,30 +222,30 @@ static bool StringIsArrayIndexHelper(con
                                      uint32_t* indexp) {
   const CharT* end = s + length;
 
   if (length == 0 || length > (sizeof("4294967294") - 1) || !IsAsciiDigit(*s)) {
     return false;
   }
 
   uint32_t c = 0, previous = 0;
-  uint32_t index = JS7_UNDEC(*s++);
+  uint32_t index = AsciiDigitToNumber(*s++);
 
   /* Don't allow leading zeros. */
   if (index == 0 && s != end) {
     return false;
   }
 
   for (; s < end; s++) {
     if (!IsAsciiDigit(*s)) {
       return false;
     }
 
     previous = index;
-    c = JS7_UNDEC(*s);
+    c = AsciiDigitToNumber(*s);
     index = 10 * index + c;
   }
 
   /* Make sure we didn't overflow. */
   if (previous < (MAX_ARRAY_INDEX / 10) ||
       (previous == (MAX_ARRAY_INDEX / 10) && c <= (MAX_ARRAY_INDEX % 10))) {
     MOZ_ASSERT(index <= MAX_ARRAY_INDEX);
     *indexp = index;
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1240,27 +1240,27 @@ static bool InterpretDollar(JSLinearStri
   if (currentDollar + 1 >= replacementEnd) {
     return false;
   }
 
   /* ES 2016 draft Mar 25, 2016 Table 46. */
   char16_t c = currentDollar[1];
   if (IsAsciiDigit(c)) {
     /* $n, $nn */
-    unsigned num = JS7_UNDEC(c);
+    unsigned num = AsciiDigitToNumber(c);
     if (num > captures.length()) {
       // The result is implementation-defined, do not substitute.
       return false;
     }
 
     const CharT* currentChar = currentDollar + 2;
     if (currentChar < replacementEnd) {
       c = *currentChar;
       if (IsAsciiDigit(c)) {
-        unsigned tmpNum = 10 * num + JS7_UNDEC(c);
+        unsigned tmpNum = 10 * num + AsciiDigitToNumber(c);
         // If num > captures.length(), the result is implementation-defined.
         // Consume next character only if num <= captures.length().
         if (tmpNum <= captures.length()) {
           currentChar++;
           num = tmpNum;
         }
       }
     }
--- a/js/src/util/Text.h
+++ b/js/src/util/Text.h
@@ -12,47 +12,48 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/Utf8.h"
 
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string>
+#include <type_traits>
 
 #include "jsutil.h"
 #include "NamespaceImports.h"
 
 #include "js/Utility.h"
 #include "util/Unicode.h"
 #include "vm/Printer.h"
 
 class JSLinearString;
 
-/*
- * Shorthands for ASCII (7-bit) decimal and hex conversion.
- * Manually inline isdigit and isxdigit for performance; MSVC doesn't do this
- * for us.
- */
-#define JS7_UNDEC(c) ((c) - '0')
-
 static MOZ_ALWAYS_INLINE size_t js_strlen(const char16_t* s) {
   return std::char_traits<char16_t>::length(s);
 }
 
 template <typename CharT>
 extern const CharT* js_strchr_limit(const CharT* s, char16_t c,
                                     const CharT* limit);
 
 extern int32_t js_fputs(const char16_t* s, FILE* f);
 
 namespace js {
 
 class StringBuffer;
 
+template <typename CharT>
+constexpr uint8_t AsciiDigitToNumber(CharT c) {
+  using UnsignedCharT = std::make_unsigned_t<CharT>;
+  auto uc = static_cast<UnsignedCharT>(c);
+  return uc - '0';
+}
+
 template <typename Char1, typename Char2>
 inline bool EqualChars(const Char1* s1, const Char2* s2, size_t len) {
   return mozilla::ArrayEqual(s1, s2, len);
 }
 
 // Return less than, equal to, or greater than zero depending on whether
 // s1 is less than, equal to, or greater than s2.
 template <typename Char1, typename Char2>
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -9,16 +9,17 @@
  */
 
 #include "vm/JSContext-inl.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Sprintf.h"
+#include "mozilla/TextUtils.h"
 #include "mozilla/Unused.h"
 
 #include <ctype.h>
 #include <stdarg.h>
 #include <string.h>
 #ifdef ANDROID
 #  include <android/log.h>
 #  include <fstream>
@@ -733,17 +734,17 @@ bool ExpandErrorArgumentsHelper(JSContex
         if (!out) {
           return false;
         }
 
         fmt = efs->format;
         while (*fmt) {
           if (*fmt == '{') {
             if (isdigit(fmt[1])) {
-              int d = JS7_UNDEC(fmt[1]);
+              int d = AsciiDigitToNumber(fmt[1]);
               MOZ_RELEASE_ASSERT(d < args.count());
               strncpy(out, args.args(d), args.lengths(d));
               out += args.lengths(d);
               fmt += 3;
 #ifdef DEBUG
               expandedArgs++;
 #endif
               continue;
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -1090,24 +1090,24 @@ bool JSFlatString::isIndexSlow(const Cha
 
   /*
    * Make sure to account for the '\0' at the end of characters, dereferenced
    * in the loop below.
    */
   RangedPtr<const CharT> cp(s, length + 1);
   const RangedPtr<const CharT> end(s + length, s, length + 1);
 
-  uint32_t index = JS7_UNDEC(*cp++);
+  uint32_t index = AsciiDigitToNumber(*cp++);
   uint32_t oldIndex = 0;
   uint32_t c = 0;
 
   if (index != 0) {
     while (IsAsciiDigit(*cp)) {
       oldIndex = index;
-      c = JS7_UNDEC(*cp);
+      c = AsciiDigitToNumber(*cp);
       index = 10 * index + c;
       cp++;
     }
   }
 
   /* It's not an element if there are characters after the number. */
   if (cp != end) {
     return false;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2311,31 +2311,31 @@ bool js::StringIsTypedArrayIndex(const C
     }
   }
 
   if (!IsAsciiDigit(*s)) {
     return false;
   }
 
   uint64_t index = 0;
-  uint32_t digit = JS7_UNDEC(*s++);
+  uint32_t digit = AsciiDigitToNumber(*s++);
 
   /* Don't allow leading zeros. */
   if (digit == 0 && s != end) {
     return false;
   }
 
   index = digit;
 
   for (; s < end; s++) {
     if (!IsAsciiDigit(*s)) {
       return false;
     }
 
-    digit = JS7_UNDEC(*s);
+    digit = AsciiDigitToNumber(*s);
 
     /* Watch for overflows. */
     if ((UINT64_MAX - digit) / 10 < index) {
       index = UINT64_MAX;
     } else {
       index = 10 * index + digit;
     }
   }