Bug 798172 - part 4 - convert the jsclone bits to use Endian.h; r=Waldo
authorNathan Froyd <froydnj@mozilla.com>
Wed, 30 Jan 2013 16:47:52 -0500
changeset 138546 fa1191b1d320dfa0cfd400b65d4808ebd91d5ea2
parent 138545 f9878fed7d54bd5fd7ab2bf32400610a1c11bc03
child 138547 f12175267ab7436bb207cdd6726c776fd93b77df
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs798172
milestone23.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 798172 - part 4 - convert the jsclone bits to use Endian.h; r=Waldo
js/src/jsclone.cpp
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -1,27 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/Endian.h"
 #include "mozilla/FloatingPoint.h"
 
 #include "jsclone.h"
 #include "jsdate.h"
 #include "jstypedarray.h"
 
 #include "jstypedarrayinlines.h"
 
 #include "vm/BooleanObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
+using mozilla::LittleEndian;
+using mozilla::NativeEndian;
 
 enum StructuredDataType {
     /* Structured data types provided by the engine */
     SCTAG_FLOAT_MAX = 0xFFF00000,
     SCTAG_NULL = 0xFFFF0000,
     SCTAG_UNDEFINED,
     SCTAG_BOOLEAN,
     SCTAG_INDEX,
@@ -69,62 +72,16 @@ ArrayTypeToTag(uint32_t type)
     JS_ASSERT(type < TypedArray::TYPE_MAX);
     return static_cast<StructuredDataType>(uint32_t(SCTAG_TYPED_ARRAY_MIN) + type);
 }
 
 JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
 JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX);
 JS_STATIC_ASSERT(TypedArray::TYPE_INT8 == 0);
 
-static uint8_t
-SwapBytes(uint8_t u)
-{
-    return u;
-}
-
-static uint16_t
-SwapBytes(uint16_t u)
-{
-#ifdef IS_BIG_ENDIAN
-    return ((u & 0x00ff) << 8) | ((u & 0xff00) >> 8);
-#else
-    return u;
-#endif
-}
-
-static uint32_t
-SwapBytes(uint32_t u)
-{
-#ifdef IS_BIG_ENDIAN
-    return ((u & 0x000000ffU) << 24) |
-           ((u & 0x0000ff00U) << 8) |
-           ((u & 0x00ff0000U) >> 8) |
-           ((u & 0xff000000U) >> 24);
-#else
-    return u;
-#endif
-}
-
-static uint64_t
-SwapBytes(uint64_t u)
-{
-#ifdef IS_BIG_ENDIAN
-    return ((u & 0x00000000000000ffLLU) << 56) |
-           ((u & 0x000000000000ff00LLU) << 40) |
-           ((u & 0x0000000000ff0000LLU) << 24) |
-           ((u & 0x00000000ff000000LLU) << 8) |
-           ((u & 0x000000ff00000000LLU) >> 8) |
-           ((u & 0x0000ff0000000000LLU) >> 24) |
-           ((u & 0x00ff000000000000LLU) >> 40) |
-           ((u & 0xff00000000000000LLU) >> 56);
-#else
-    return u;
-#endif
-}
-
 bool
 js::WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
                          const JSStructuredCloneCallbacks *cb, void *cbClosure,
                          jsval transferable)
 {
     SCOutput out(cx);
     JSStructuredCloneWriter w(out, cb, cbClosure, transferable);
     return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp);
@@ -144,42 +101,42 @@ js::ReadStructuredClone(JSContext *cx, u
 }
 
 bool
 js::ClearStructuredClone(const uint64_t *data, size_t nbytes)
 {
     const uint64_t *point = data;
     const uint64_t *end = data + nbytes / 8;
 
-    uint64_t u = SwapBytes(*point++);
+    uint64_t u = LittleEndian::readUint64(point++);
     uint32_t tag = uint32_t(u >> 32);
     if (tag == SCTAG_TRANSFER_MAP_HEADER) {
         if ((TransferableMapHeader)uint32_t(u) == SCTAG_TM_NOT_MARKED) {
             while (point != end) {
-                uint64_t u = SwapBytes(*point++);
+                uint64_t u = LittleEndian::readUint64(point++);
                 uint32_t tag = uint32_t(u >> 32);
                 if (tag == SCTAG_TRANSFER_MAP) {
-                    u = SwapBytes(*point++);
+                    u = LittleEndian::readUint64(point++);
                     js_free(reinterpret_cast<void*>(u));
                 }
             }
         }
     }
 
     js_free((void *)data);
     return true;
 }
 
 bool
 js::StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
 {
     *hasTransferable = false;
 
     if (data) {
-        uint64_t u = SwapBytes(*data);
+        uint64_t u = LittleEndian::readUint64(data);
         uint32_t tag = uint32_t(u >> 32);
         if (tag == SCTAG_TRANSFER_MAP_HEADER) {
             *hasTransferable = true;
         }
     }
 
     return true;
 }
@@ -206,17 +163,17 @@ SCInput::SCInput(JSContext *cx, uint64_t
 
 bool
 SCInput::read(uint64_t *p)
 {
     if (point == end) {
         *p = 0;  /* initialize to shut GCC up */
         return eof();
     }
-    *p = SwapBytes(*point++);
+    *p = LittleEndian::readUint64(point++);
     return true;
 }
 
 bool
 SCInput::readPair(uint32_t *tagp, uint32_t *datap)
 {
     uint64_t u;
     bool ok = read(&u);
@@ -227,17 +184,17 @@ SCInput::readPair(uint32_t *tagp, uint32
     return ok;
 }
 
 bool
 SCInput::get(uint64_t *p)
 {
     if (point == end)
         return eof();
-    *p = SwapBytes(*point);
+    *p = LittleEndian::readUint64(point);
     return true;
 }
 
 bool
 SCInput::getPair(uint32_t *tagp, uint32_t *datap)
 {
     uint64_t u;
     if (!get(&u))
@@ -248,17 +205,17 @@ SCInput::getPair(uint32_t *tagp, uint32_
     return true;
 }
 
 bool
 SCInput::replace(uint64_t u)
 {
     if (point == end)
        return eof();
-    *point = SwapBytes(u);
+    LittleEndian::writeUint64(point, u);
     return true;
 }
 
 bool
 SCInput::replacePair(uint32_t tag, uint32_t data)
 {
     return replace(PairToUInt64(tag, data));
 }
@@ -281,38 +238,45 @@ SCInput::readDouble(double *p)
         double d;
     } pun;
     if (!read(&pun.u))
         return false;
     *p = CanonicalizeNan(pun.d);
     return true;
 }
 
+template <typename T>
+static void
+copyAndSwapFromLittleEndian(T *dest, const void *src, size_t nelems)
+{
+    NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems);
+}
+
+template <>
+void
+copyAndSwapFromLittleEndian(uint8_t *dest, const void *src, size_t nelems)
+{
+    memcpy(dest, src, nelems);
+}
+
 template <class T>
 bool
 SCInput::readArray(T *p, size_t nelems)
 {
     JS_STATIC_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
 
     /*
      * Fail if nelems is so huge as to make JS_HOWMANY overflow or if nwords is
      * larger than the remaining data.
      */
     size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
     if (nelems + sizeof(uint64_t) / sizeof(T) - 1 < nelems || nwords > size_t(end - point))
         return eof();
 
-    if (sizeof(T) == 1) {
-        js_memcpy(p, point, nelems);
-    } else {
-        const T *q = (const T *) point;
-        const T *qend = q + nelems;
-        while (q != qend)
-            *p++ = ::SwapBytes(*q++);
-    }
+    copyAndSwapFromLittleEndian(p, point, nelems);
     point += nwords;
     return true;
 }
 
 bool
 SCInput::readBytes(void *p, size_t nbytes)
 {
     return readArray((uint8_t *) p, nbytes);
@@ -336,17 +300,17 @@ SCInput::readPtr(void **p)
     return ret;
 }
 
 SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {}
 
 bool
 SCOutput::write(uint64_t u)
 {
-    return buf.append(SwapBytes(u));
+    return buf.append(NativeEndian::swapToLittleEndian(u));
 }
 
 bool
 SCOutput::writePair(uint32_t tag, uint32_t data)
 {
     /*
      * As it happens, the tag word appears after the data word in the output.
      * This is because exponents occupy the last 2 bytes of doubles on the
@@ -388,16 +352,30 @@ ReinterpretPairAsDouble(uint32_t tag, ui
 }
 
 bool
 SCOutput::writeDouble(double d)
 {
     return write(ReinterpretDoubleAsUInt64(CanonicalizeNan(d)));
 }
 
+template <typename T>
+static void
+copyAndSwapToLittleEndian(void *dest, const T *src, size_t nelems)
+{
+    NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems);
+}
+
+template <>
+void
+copyAndSwapToLittleEndian(void *dest, const uint8_t *src, size_t nelems)
+{
+    memcpy(dest, src, nelems);
+}
+
 template <class T>
 bool
 SCOutput::writeArray(const T *p, size_t nelems)
 {
     JS_ASSERT(8 % sizeof(T) == 0);
     JS_ASSERT(sizeof(uint64_t) % sizeof(T) == 0);
 
     if (nelems == 0)
@@ -410,23 +388,17 @@ SCOutput::writeArray(const T *p, size_t 
     size_t nwords = JS_HOWMANY(nelems, sizeof(uint64_t) / sizeof(T));
     size_t start = buf.length();
     if (!buf.growByUninitialized(nwords))
         return false;
 
     buf.back() = 0;  /* zero-pad to an 8-byte boundary */
 
     T *q = (T *) &buf[start];
-    if (sizeof(T) == 1) {
-        js_memcpy(q, p, nelems);
-    } else {
-        const T *pend = p + nelems;
-        while (p != pend)
-            *q++ = ::SwapBytes(*p++);
-    }
+    copyAndSwapToLittleEndian(q, p, nelems);
     return true;
 }
 
 bool
 SCOutput::writeBytes(const void *p, size_t nbytes)
 {
     return writeArray((const uint8_t *) p, nbytes);
 }