Bug 1413049 - Part 1: Add methods to EndianUtils for pointer-sized integers. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 01 Mar 2018 11:05:13 -0600
changeset 461321 6726bc85d05ef136bfcadfba96984ae5f5836fc8
parent 461320 e1327304773f521e8decb2a450edac26e4c24b70
child 461322 960a3d703f4b30534edb77db380a45fd51de5088
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1413049
milestone60.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 1413049 - Part 1: Add methods to EndianUtils for pointer-sized integers. r=Waldo.
mfbt/EndianUtils.h
mfbt/tests/TestEndian.cpp
--- a/mfbt/EndianUtils.h
+++ b/mfbt/EndianUtils.h
@@ -4,17 +4,19 @@
  * 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/. */
 
 /* Functions for reading and writing integers in various endiannesses. */
 
 /*
  * The classes LittleEndian and BigEndian expose static methods for
  * reading and writing 16-, 32-, and 64-bit signed and unsigned integers
- * in their respective endianness.  The naming scheme is:
+ * in their respective endianness.  The addresses read from or written
+ * to may be misaligned (although misaligned accesses may incur
+ * architecture-specific performance costs).  The naming scheme is:
  *
  * {Little,Big}Endian::{read,write}{Uint,Int}<bitsize>
  *
  * For instance, LittleEndian::readInt32 will read a 32-bit signed
  * integer from memory in little endian format.  Similarly,
  * BigEndian::writeUint16 will write a 16-bit unsigned integer to memory
  * in big-endian format.
  *
@@ -356,16 +358,22 @@ protected:
   }
 
   /** Read a uint64_t in ThisEndian endianness from |aPtr| and return it. */
   static MOZ_MUST_USE uint64_t readUint64(const void* aPtr)
   {
     return read<uint64_t>(aPtr);
   }
 
+  /** Read a uintptr_t in ThisEndian endianness from |aPtr| and return it. */
+  static MOZ_MUST_USE uintptr_t readUintptr(const void* aPtr)
+  {
+    return read<uintptr_t>(aPtr);
+  }
+
   /** Read an int16_t in ThisEndian endianness from |aPtr| and return it. */
   static MOZ_MUST_USE int16_t readInt16(const void* aPtr)
   {
     return read<int16_t>(aPtr);
   }
 
   /** Read an int32_t in ThisEndian endianness from |aPtr| and return it. */
   static MOZ_MUST_USE int32_t readInt32(const void* aPtr)
@@ -374,16 +382,22 @@ protected:
   }
 
   /** Read an int64_t in ThisEndian endianness from |aPtr| and return it. */
   static MOZ_MUST_USE int64_t readInt64(const void* aPtr)
   {
     return read<int64_t>(aPtr);
   }
 
+  /** Read an intptr_t in ThisEndian endianness from |aPtr| and return it. */
+  static MOZ_MUST_USE intptr_t readIntptr(const void* aPtr)
+  {
+    return read<intptr_t>(aPtr);
+  }
+
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeUint16(void* aPtr, uint16_t aValue)
   {
     write(aPtr, aValue);
   }
 
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeUint32(void* aPtr, uint32_t aValue)
@@ -393,16 +407,22 @@ protected:
 
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeUint64(void* aPtr, uint64_t aValue)
   {
     write(aPtr, aValue);
   }
 
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeUintptr(void* aPtr, uintptr_t aValue)
+  {
+    write(aPtr, aValue);
+  }
+
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeInt16(void* aPtr, int16_t aValue)
   {
     write(aPtr, aValue);
   }
 
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeInt32(void* aPtr, int32_t aValue)
   {
@@ -410,16 +430,22 @@ protected:
   }
 
   /** Write |aValue| to |aPtr| using ThisEndian endianness. */
   static void writeInt64(void* aPtr, int64_t aValue)
   {
     write(aPtr, aValue);
   }
 
+  /** Write |aValue| to |aPtr| using ThisEndian endianness. */
+  static void writeIntptr(void* aPtr, intptr_t aValue)
+  {
+    write(aPtr, aValue);
+  }
+
   /*
    * Converts a value of type T to little-endian format.
    *
    * This function is intended for cases where you have data in your
    * native-endian format and you need it to appear in little-endian
    * format for transmission.
    */
   template<typename T>
@@ -625,25 +651,29 @@ class EndianReadWrite : public Endian<Th
 {
 private:
   typedef Endian<ThisEndian> super;
 
 public:
   using super::readUint16;
   using super::readUint32;
   using super::readUint64;
+  using super::readUintptr;
   using super::readInt16;
   using super::readInt32;
   using super::readInt64;
+  using super::readIntptr;
   using super::writeUint16;
   using super::writeUint32;
   using super::writeUint64;
+  using super::writeUintptr;
   using super::writeInt16;
   using super::writeInt32;
   using super::writeInt64;
+  using super::writeIntptr;
 };
 
 } /* namespace detail */
 
 class LittleEndian final : public detail::EndianReadWrite<detail::Little>
 {};
 
 class BigEndian final : public detail::EndianReadWrite<detail::Big>
--- a/mfbt/tests/TestEndian.cpp
+++ b/mfbt/tests/TestEndian.cpp
@@ -362,16 +362,28 @@ main()
   MOZ_RELEASE_ASSERT(
     BigEndian::readUint32(&unsigned_bytes[0]) == 0x1020304U);
 
   MOZ_RELEASE_ASSERT(
     LittleEndian::readUint64(&unsigned_bytes[0]) == 0x807060504030201ULL);
   MOZ_RELEASE_ASSERT(
     BigEndian::readUint64(&unsigned_bytes[0]) == 0x102030405060708ULL);
 
+  if (sizeof(uintptr_t) == 8) {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUintptr(&unsigned_bytes[0]) == 0x0807060504030201ULL);
+    MOZ_RELEASE_ASSERT(
+      BigEndian::readUintptr(&unsigned_bytes[0]) == 0x0102030405060708ULL);
+  } else {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUintptr(&unsigned_bytes[0]) == 0x04030201U);
+    MOZ_RELEASE_ASSERT(
+      BigEndian::readUintptr(&unsigned_bytes[0]) == 0x01020304U);
+  }
+
   LittleEndian::writeUint16(&buffer[0], 0x201);
   MOZ_RELEASE_ASSERT(
     memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
   BigEndian::writeUint16(&buffer[0], 0x102);
   MOZ_RELEASE_ASSERT(
     memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint16_t)) == 0);
 
   LittleEndian::writeUint32(&buffer[0], 0x4030201U);
@@ -383,31 +395,63 @@ main()
 
   LittleEndian::writeUint64(&buffer[0], 0x807060504030201ULL);
   MOZ_RELEASE_ASSERT(
     memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
   BigEndian::writeUint64(&buffer[0], 0x102030405060708ULL);
   MOZ_RELEASE_ASSERT(
     memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uint64_t)) == 0);
 
+  memset(&buffer[0], 0xff, sizeof(buffer));
+  LittleEndian::writeUintptr(&buffer[0], uintptr_t(0x0807060504030201ULL));
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uintptr_t)) == 0);
+  if (sizeof(uintptr_t) == 4) {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
+  }
+
+  memset(&buffer[0], 0xff, sizeof(buffer));
+  if (sizeof(uintptr_t) == 8) {
+    BigEndian::writeUintptr(&buffer[0], uintptr_t(0x0102030405060708ULL));
+  } else {
+    BigEndian::writeUintptr(&buffer[0], uintptr_t(0x01020304U));
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
+  }
+  MOZ_RELEASE_ASSERT(
+    memcmp(&unsigned_bytes[0], &buffer[0], sizeof(uintptr_t)) == 0);
+
   MOZ_RELEASE_ASSERT(
     LittleEndian::readInt16(&signed_bytes[0]) == int16_t(0xf2f1));
   MOZ_RELEASE_ASSERT(
     BigEndian::readInt16(&signed_bytes[0]) == int16_t(0xf1f2));
 
   MOZ_RELEASE_ASSERT(
     LittleEndian::readInt32(&signed_bytes[0]) == int32_t(0xf4f3f2f1));
   MOZ_RELEASE_ASSERT(
     BigEndian::readInt32(&signed_bytes[0]) == int32_t(0xf1f2f3f4));
 
   MOZ_RELEASE_ASSERT(
     LittleEndian::readInt64(&signed_bytes[0]) == int64_t(0xf8f7f6f5f4f3f2f1LL));
   MOZ_RELEASE_ASSERT(
     BigEndian::readInt64(&signed_bytes[0]) == int64_t(0xf1f2f3f4f5f6f7f8LL));
 
+  if (sizeof(uintptr_t) == 8) {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf8f7f6f5f4f3f2f1LL));
+    MOZ_RELEASE_ASSERT(
+      BigEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf1f2f3f4f5f6f7f8LL));
+  } else {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf4f3f2f1));
+    MOZ_RELEASE_ASSERT(
+      BigEndian::readIntptr(&signed_bytes[0]) == intptr_t(0xf1f2f3f4));
+  }
+
   LittleEndian::writeInt16(&buffer[0], int16_t(0xf2f1));
   MOZ_RELEASE_ASSERT(
     memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
   BigEndian::writeInt16(&buffer[0], int16_t(0xf1f2));
   MOZ_RELEASE_ASSERT(
     memcmp(&signed_bytes[0], &buffer[0], sizeof(int16_t)) == 0);
 
   LittleEndian::writeInt32(&buffer[0], 0xf4f3f2f1);
@@ -419,16 +463,36 @@ main()
 
   LittleEndian::writeInt64(&buffer[0], 0xf8f7f6f5f4f3f2f1LL);
   MOZ_RELEASE_ASSERT(
     memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
   BigEndian::writeInt64(&buffer[0], 0xf1f2f3f4f5f6f7f8LL);
   MOZ_RELEASE_ASSERT(
     memcmp(&signed_bytes[0], &buffer[0], sizeof(int64_t)) == 0);
 
+  memset(&buffer[0], 0xff, sizeof(buffer));
+  LittleEndian::writeIntptr(&buffer[0], intptr_t(0xf8f7f6f5f4f3f2f1LL));
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(intptr_t)) == 0);
+  if (sizeof(intptr_t) == 4) {
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
+  }
+
+  memset(&buffer[0], 0xff, sizeof(buffer));
+  if (sizeof(intptr_t) == 8) {
+    BigEndian::writeIntptr(&buffer[0], intptr_t(0xf1f2f3f4f5f6f7f8LL));
+  } else {
+    BigEndian::writeIntptr(&buffer[0], intptr_t(0xf1f2f3f4));
+    MOZ_RELEASE_ASSERT(
+      LittleEndian::readUint32(&buffer[4]) == 0xffffffffU);
+  }
+  MOZ_RELEASE_ASSERT(
+    memcmp(&signed_bytes[0], &buffer[0], sizeof(intptr_t)) == 0);
+
   TestSingleSwap(uint16_t(0xf2f1), uint16_t(0xf1f2));
   TestSingleSwap(uint32_t(0xf4f3f2f1), uint32_t(0xf1f2f3f4));
   TestSingleSwap(uint64_t(0xf8f7f6f5f4f3f2f1), uint64_t(0xf1f2f3f4f5f6f7f8));
 
   TestSingleSwap(int16_t(0xf2f1), int16_t(0xf1f2));
   TestSingleSwap(int32_t(0xf4f3f2f1), int32_t(0xf1f2f3f4));
   TestSingleSwap(int64_t(0xf8f7f6f5f4f3f2f1), int64_t(0xf1f2f3f4f5f6f7f8));