Bug 1542736 - Part 1: Replace JS7_UNHEX with mozilla::AsciiAlphanumericToNumber. r=jwalden
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 11 Apr 2019 11:33:56 +0000
changeset 469052 5b6bf24882cee31b0d344a0fe1f5f7d5076d3cec
parent 469051 cb9e9d32e5213700d73b041daa4971f6a4785497
child 469053 bac7b9ec895ca1b8da43d3f2b8e1c9f191dac508
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 1: Replace JS7_UNHEX with mozilla::AsciiAlphanumericToNumber. r=jwalden This avoids a call to std::tolower, making hex-conversions slightly faster. Differential Revision: https://phabricator.services.mozilla.com/D26504
js/src/builtin/String.cpp
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/util/Text.h
js/src/vm/JSONParser.cpp
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -7,16 +7,17 @@
 #include "builtin/String.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Range.h"
+#include "mozilla/TextUtils.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
 
 #include <ctype.h>
 #include <limits>
 #include <string.h>
 
 #include "jsapi.h"
@@ -61,16 +62,17 @@
 #include "vm/StringType-inl.h"
 #include "vm/TypeInference-inl.h"
 
 using namespace js;
 
 using JS::Symbol;
 using JS::SymbolCode;
 
+using mozilla::AsciiAlphanumericToNumber;
 using mozilla::CheckedInt;
 using mozilla::IsNaN;
 using mozilla::IsSame;
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
 
 using JS::AutoCheckCannotGC;
 using JS::AutoStableStringChars;
@@ -221,38 +223,40 @@ static bool str_escape(JSContext* cx, un
 
   args.rval().setString(res);
   return true;
 }
 
 template <typename CharT>
 static inline bool Unhex4(const RangedPtr<const CharT> chars,
                           char16_t* result) {
-  char16_t a = chars[0], b = chars[1], c = chars[2], d = chars[3];
+  CharT a = chars[0], b = chars[1], c = chars[2], d = chars[3];
 
   if (!(JS7_ISHEX(a) && JS7_ISHEX(b) && JS7_ISHEX(c) && JS7_ISHEX(d))) {
     return false;
   }
 
-  *result =
-      (((((JS7_UNHEX(a) << 4) + JS7_UNHEX(b)) << 4) + JS7_UNHEX(c)) << 4) +
-      JS7_UNHEX(d);
+  char16_t unhex = AsciiAlphanumericToNumber(a);
+  unhex = (unhex << 4) + AsciiAlphanumericToNumber(b);
+  unhex = (unhex << 4) + AsciiAlphanumericToNumber(c);
+  unhex = (unhex << 4) + AsciiAlphanumericToNumber(d);
+  *result = unhex;
   return true;
 }
 
 template <typename CharT>
 static inline bool Unhex2(const RangedPtr<const CharT> chars,
                           char16_t* result) {
-  char16_t a = chars[0], b = chars[1];
+  CharT a = chars[0], b = chars[1];
 
   if (!(JS7_ISHEX(a) && JS7_ISHEX(b))) {
     return false;
   }
 
-  *result = (JS7_UNHEX(a) << 4) + JS7_UNHEX(b);
+  *result = (AsciiAlphanumericToNumber(a) << 4) + AsciiAlphanumericToNumber(b);
   return true;
 }
 
 template <typename CharT>
 static bool Unescape(StringBuffer& sb,
                      const mozilla::Range<const CharT> chars) {
   // Step 2.
   uint32_t length = chars.length();
@@ -3975,17 +3979,18 @@ static DecodeResult Decode(StringBuffer&
       if ((k + 2) >= length) {
         return Decode_BadUri;
       }
 
       if (!JS7_ISHEX(chars[k + 1]) || !JS7_ISHEX(chars[k + 2])) {
         return Decode_BadUri;
       }
 
-      uint32_t B = JS7_UNHEX(chars[k + 1]) * 16 + JS7_UNHEX(chars[k + 2]);
+      uint32_t B = AsciiAlphanumericToNumber(chars[k + 1]) * 16 +
+                   AsciiAlphanumericToNumber(chars[k + 2]);
       k += 2;
       if (B < 128) {
         Latin1Char ch = Latin1Char(B);
         if (reservedSet && reservedSet[ch]) {
           continue;
         }
 
         if (!appendRange(startAppend, start)) {
@@ -4015,17 +4020,18 @@ static DecodeResult Decode(StringBuffer&
           if (chars[k] != '%') {
             return Decode_BadUri;
           }
 
           if (!JS7_ISHEX(chars[k + 1]) || !JS7_ISHEX(chars[k + 2])) {
             return Decode_BadUri;
           }
 
-          B = JS7_UNHEX(chars[k + 1]) * 16 + JS7_UNHEX(chars[k + 2]);
+          B = AsciiAlphanumericToNumber(chars[k + 1]) * 16 +
+              AsciiAlphanumericToNumber(chars[k + 2]);
           if ((B & 0xC0) != 0x80) {
             return Decode_BadUri;
           }
 
           k += 2;
           octets[j] = char(B);
         }
 
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -39,16 +39,17 @@
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 
 using mozilla::ArrayLength;
+using mozilla::AsciiAlphanumericToNumber;
 using mozilla::AssertedCast;
 using mozilla::DecodeOneUtf8CodePoint;
 using mozilla::IsAscii;
 using mozilla::IsAsciiAlpha;
 using mozilla::IsAsciiDigit;
 using mozilla::IsTrailingUnit;
 using mozilla::MakeScopeExit;
 using mozilla::MakeSpan;
@@ -1545,17 +1546,17 @@ uint32_t GeneralTokenStreamChars<Unit, A
     ungetCodeUnit(unit);
     MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == Unit('\\'));
     return 0;
   }
 
   char16_t v;
   unit = getCodeUnit();
   if (JS7_ISHEX(unit) && this->sourceUnits.matchHexDigits(3, &v)) {
-    *codePoint = (JS7_UNHEX(unit) << 12) | v;
+    *codePoint = (AsciiAlphanumericToNumber(unit) << 12) | v;
     return 5;
   }
 
   if (unit == '{') {
     return matchExtendedUnicodeEscape(codePoint);
   }
 
   // NOTE: |unit| may be EOF here, so this ungets either one or two units.
@@ -1578,17 +1579,17 @@ GeneralTokenStreamChars<Unit, AnyCharsAc
   while (unit == '0') {
     leadingZeroes++;
     unit = getCodeUnit();
   }
 
   size_t i = 0;
   uint32_t code = 0;
   while (JS7_ISHEX(unit) && i < 6) {
-    code = (code << 4) | JS7_UNHEX(unit);
+    code = (code << 4) | AsciiAlphanumericToNumber(unit);
     unit = getCodeUnit();
     i++;
   }
 
   uint32_t gotten =
       2 +                  // 'u{'
       leadingZeroes + i +  // significant hexdigits
       (unit != EOF);       // subtract a get if it didn't contribute to length
@@ -3184,17 +3185,17 @@ bool TokenStreamSpecific<Unit, AnyCharsA
                                                     InvalidEscapeType::Unicode);
                   valid = false;
                   break;
                 }
                 reportInvalidEscapeError(start, InvalidEscapeType::Unicode);
                 return false;
               }
 
-              code = (code << 4) | JS7_UNHEX(u3);
+              code = (code << 4) | AsciiAlphanumericToNumber(u3);
               if (code > unicode::NonBMPMax) {
                 if (parsingTemplate) {
                   TokenStreamAnyChars& anyChars = anyCharsAccess();
                   anyChars.setInvalidTemplateEscape(
                       start + 3, InvalidEscapeType::UnicodeOverflow);
                   valid = false;
                   break;
                 }
@@ -3219,17 +3220,17 @@ bool TokenStreamSpecific<Unit, AnyCharsA
           }  // end of delimited Unicode escape handling
 
           // Otherwise it must be a fixed-length \uXXXX Unicode escape.
           // If it isn't, this is usually an error -- but if this is a
           // template literal, we must defer error reporting because
           // malformed escapes are okay in *tagged* template literals.
           char16_t v;
           if (JS7_ISHEX(c2) && this->sourceUnits.matchHexDigits(3, &v)) {
-            unit = (JS7_UNHEX(c2) << 12) | v;
+            unit = (AsciiAlphanumericToNumber(c2) << 12) | v;
           } else {
             // Beware: |c2| may not be an ASCII code point here!
             ungetCodeUnit(c2);
             uint32_t start = this->sourceUnits.offset() - 2;
             if (parsingTemplate) {
               TokenStreamAnyChars& anyChars = anyCharsAccess();
               anyChars.setInvalidTemplateEscape(start,
                                                 InvalidEscapeType::Unicode);
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -1219,17 +1219,17 @@ class SourceUnits {
 
     char16_t v = 0;
     for (uint8_t i = 0; i < n; i++) {
       auto unit = CodeUnitValue(ptr[i]);
       if (!JS7_ISHEX(unit)) {
         return false;
       }
 
-      v = (v << 4) | JS7_UNHEX(unit);
+      v = (v << 4) | mozilla::AsciiAlphanumericToNumber(unit);
     }
 
     *out = v;
     ptr += n;
     return true;
   }
 
   bool matchCodeUnits(const char* chars, uint8_t length) {
--- a/js/src/util/Text.h
+++ b/js/src/util/Text.h
@@ -8,17 +8,16 @@
 #define util_Text_h
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/Utf8.h"
 
-#include <ctype.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string>
 
 #include "jsutil.h"
 #include "NamespaceImports.h"
 
@@ -34,18 +33,16 @@ class JSLinearString;
  * for us.
  */
 #define JS7_ISA2F(c) \
   ((((((unsigned)(c)) - 'a') <= 5) || (((unsigned)(c)) - 'A') <= 5))
 #define JS7_UNDEC(c) ((c) - '0')
 #define JS7_ISOCT(c) ((((unsigned)(c)) - '0') <= 7)
 #define JS7_UNOCT(c) (JS7_UNDEC(c))
 #define JS7_ISHEX(c) ((c) < 128 && (mozilla::IsAsciiDigit(c) || JS7_ISA2F(c)))
-#define JS7_UNHEX(c) \
-  (unsigned)(mozilla::IsAsciiDigit(c) ? (c) - '0' : 10 + tolower(c) - 'a')
 
 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);
--- a/js/src/vm/JSONParser.cpp
+++ b/js/src/vm/JSONParser.cpp
@@ -18,16 +18,17 @@
 #include "builtin/Array.h"
 #include "util/StringBuffer.h"
 #include "vm/Realm.h"
 
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
+using mozilla::AsciiAlphanumericToNumber;
 using mozilla::IsAsciiDigit;
 using mozilla::RangedPtr;
 
 JSONParserBase::~JSONParserBase() {
   for (size_t i = 0; i < stack.length(); i++) {
     if (stack[i].state == FinishArrayElement) {
       js_delete(&stack[i].elements());
     } else {
@@ -217,18 +218,20 @@ JSONParserBase::Token JSONParser<CharT>:
             current += 3;
           } else {
             MOZ_CRASH("logic error determining first erroneous character");
           }
 
           error("bad Unicode escape");
           return token(Error);
         }
-        c = (JS7_UNHEX(current[0]) << 12) | (JS7_UNHEX(current[1]) << 8) |
-            (JS7_UNHEX(current[2]) << 4) | (JS7_UNHEX(current[3]));
+        c = (AsciiAlphanumericToNumber(current[0]) << 12) |
+            (AsciiAlphanumericToNumber(current[1]) << 8) |
+            (AsciiAlphanumericToNumber(current[2]) << 4) |
+            (AsciiAlphanumericToNumber(current[3]));
         current += 4;
         break;
 
       default:
         current--;
         error("bad escaped character");
         return token(Error);
     }