Backed out 12 changesets (bug 1565515) hazard failures on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Tue, 30 Jul 2019 17:16:15 +0300
changeset 485311 bb23c8be138d1eaf274bdfdfeb7ad3dceb51b93b
parent 485310 1b513d98a80eb58847f20d4ac698ccb012ab108d
child 485312 ce76fa05c90f3f24f8db09950eadd4a8cdec9088
push id36364
push userdvarga@mozilla.com
push dateTue, 30 Jul 2019 21:50:30 +0000
treeherdermozilla-central@e259d43073bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1565515
milestone70.0a1
backs out4d8c2c1bce2d2199740e7fcd74af458b52884f71
8619e09b03bb9955705e000d26d4c22c3c942204
d70293010941798f0a7ee73f79e9952c7ed53ffd
90fb12799ecdadff1e1117219d8e698609660257
93be9fcab443679da38b684121ec37fe11590cfc
91f546c40f98ca71b5c3a152fc1d1e3a229cceab
2c0fb0c0e228c9f1116c21885374839a6986dea3
57ed49a17c9dacc7ae115f7ed3ddfa31566286d3
75cb7938f704720331adb4e689e95a1c6977a882
2359da4989a7046a8e766d7335c34e1748490d55
8f3493b2cae181239af4386f3ff790d148ee28c5
e0aa82bed5fac713007044546c4db1d4a1367da2
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
Backed out 12 changesets (bug 1565515) hazard failures on a CLOSED TREE Backed out changeset 4d8c2c1bce2d (bug 1565515) Backed out changeset 8619e09b03bb (bug 1565515) Backed out changeset d70293010941 (bug 1565515) Backed out changeset 90fb12799ecd (bug 1565515) Backed out changeset 93be9fcab443 (bug 1565515) Backed out changeset 91f546c40f98 (bug 1565515) Backed out changeset 2c0fb0c0e228 (bug 1565515) Backed out changeset 57ed49a17c9d (bug 1565515) Backed out changeset 75cb7938f704 (bug 1565515) Backed out changeset 2359da4989a7 (bug 1565515) Backed out changeset 8f3493b2cae1 (bug 1565515) Backed out changeset e0aa82bed5fa (bug 1565515)
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/Key.cpp
dom/indexedDB/Key.h
dom/indexedDB/test/helpers.js
dom/indexedDB/test/unit/test_keys.js
dom/indexedDB/test/unit/xpcshell-head-parent-process.js
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -500,16 +500,18 @@ void IDBCursor::ContinuePrimaryKey(JSCon
       if (result.Is(Invalid, aRv)) {
         aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
       }
       return;
     }
     key = tmp;
   }
 
+  const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
+
   if (key.IsUnset()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     return;
   }
 
   Key primaryKey;
   result = primaryKey.SetFromJSVal(aCx, aPrimaryKey, aRv);
   if (!result.Is(Ok, aRv)) {
@@ -519,18 +521,16 @@ void IDBCursor::ContinuePrimaryKey(JSCon
     return;
   }
 
   if (primaryKey.IsUnset()) {
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     return;
   }
 
-  const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
-
   switch (mDirection) {
     case NEXT:
       if (key < sortKey || (key == sortKey && primaryKey <= mPrimaryKey)) {
         aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
         return;
       }
       break;
 
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -54,17 +54,17 @@ namespace indexedDB {
  When encoding strings, we use variable-size encoding per the following table
 
  Chars 0         - 7E           are encoded as 0xxxxxxx with 1 added
  Chars 7F        - (3FFF+7F)    are encoded as 10xxxxxx xxxxxxxx with 7F
                                 subtracted
  Chars (3FFF+80) - FFFF         are encoded as 11xxxxxx xxxxxxxx xx000000
 
  This ensures that the first byte is never encoded as 0, which means that the
- string terminator (per basic-strategy table) sorts before any character.
+ string terminator (per basic-stategy table) sorts before any character.
  The reason that (3FFF+80) - FFFF is encoded "shifted up" 6 bits is to maximize
  the chance that the last character is 0. See below for why.
 
  When encoding binaries, the algorithm is the same to how strings are encoded.
  Since each octet in binary is in the range of [0-255], it'll take 1 to 2
  encoded unicode bytes.
 
  When encoding Arrays, we use an additional trick. Rather than adding a byte
@@ -118,40 +118,44 @@ IDBResult<void, IDBSpecialValue::Invalid
     TrimBuffer();
   }
   return result;
 }
 
 // |aPos| should point to the type indicator.
 // The returned length doesn't include the type indicator
 // or the terminator.
-// static
-uint32_t Key::LengthOfEncodedBinary(const EncodedDataType* aPos,
-                                    const EncodedDataType* aEnd) {
+static size_t LengthOfEncodedBinary(const unsigned char* aPos,
+                                    const unsigned char* aEnd) {
   MOZ_ASSERT(*aPos % Key::eMaxType == Key::eBinary, "Don't call me!");
-  const EncodedDataType* encodedSectionEnd;
-  return CalcDecodedStringySize<uint8_t>(aPos + 1, aEnd, &encodedSectionEnd);
+  auto iter = ++aPos;
+  for (; iter < aEnd && *iter != Key::eTerminator; ++iter) {
+    if (*iter & 0x80) {
+      iter++;
+    }
+  }
+  return iter - aPos;
 }
 
 IDBResult<void, IDBSpecialValue::Invalid> Key::ToLocaleBasedKey(
     Key& aTarget, const nsCString& aLocale, ErrorResult& aRv) const {
   if (IsUnset()) {
     aTarget.Unset();
     return Ok();
   }
 
   if (IsFloat() || IsDate() || IsBinary()) {
     aTarget.mBuffer = mBuffer;
     return Ok();
   }
 
   aTarget.mBuffer.Truncate();
 
-  auto* it = BufferStart();
-  auto* end = BufferEnd();
+  auto* it = reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
+  auto* end = reinterpret_cast<const unsigned char*>(mBuffer.EndReading());
 
   // First we do a pass and see if there are any strings in this key. We only
   // want to copy/decode when necessary.
   bool canShareBuffers = true;
   while (it < end) {
     auto type = *it % eMaxType;
     if (type == eTerminator) {
       it++;
@@ -174,17 +178,17 @@ IDBResult<void, IDBSpecialValue::Invalid
     MOZ_ASSERT(it == end);
     aTarget.mBuffer = mBuffer;
     return Ok();
   }
 
   aTarget.mBuffer.SetCapacity(mBuffer.Length());
 
   // A string was found, so we need to copy the data we've read so far
-  auto* start = BufferStart();
+  auto* start = reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
   if (it > start) {
     char* buffer;
     if (!aTarget.mBuffer.GetMutableData(&buffer, it - start)) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return Exception;
     }
 
     std::copy(start, it, buffer);
@@ -377,18 +381,18 @@ IDBResult<void, IDBSpecialValue::Invalid
   }
 
   // Otherwise
   // Return invalid.
   return Invalid;
 }
 
 // static
-nsresult Key::DecodeJSValInternal(const EncodedDataType*& aPos,
-                                  const EncodedDataType* aEnd, JSContext* aCx,
+nsresult Key::DecodeJSValInternal(const unsigned char*& aPos,
+                                  const unsigned char* aEnd, JSContext* aCx,
                                   uint8_t aTypeOffset,
                                   JS::MutableHandle<JS::Value> aVal,
                                   uint16_t aRecursionDepth) {
   if (NS_WARN_IF(aRecursionDepth == kMaxRecursionDepth)) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   if (*aPos - aTypeOffset >= eArray) {
@@ -497,17 +501,17 @@ IDBResult<void, IDBSpecialValue::Invalid
     const T* aStart, const T* aEnd, uint8_t aType, ErrorResult& aRv) {
   // First measure how long the encoded string will be.
   if (NS_WARN_IF(aStart > aEnd || UINT32_MAX - 2 < uintptr_t(aEnd - aStart))) {
     IDB_REPORT_INTERNAL_ERR();
     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return Exception;
   }
 
-  // The +2 is for initial aType and trailing 0. We'll compensate for multi-byte
+  // The +2 is for initial 3 and trailing 0. We'll compensate for multi-byte
   // chars below.
   uint32_t checkedSize = aEnd - aStart;
   CheckedUint32 size = checkedSize;
   size += 2;
 
   MOZ_ASSERT(size.isValid());
 
   const T* start = aStart;
@@ -600,117 +604,76 @@ IDBResult<void, IDBSpecialValue::Invalid
     return Exception;
   }
 
   return EncodeString(keyBuffer.Elements(),
                       keyBuffer.Elements() + sortKeyLength, aTypeOffset, aRv);
 }
 
 // static
-nsresult Key::DecodeJSVal(const EncodedDataType*& aPos,
-                          const EncodedDataType* aEnd, JSContext* aCx,
-                          JS::MutableHandle<JS::Value> aVal) {
+nsresult Key::DecodeJSVal(const unsigned char*& aPos, const unsigned char* aEnd,
+                          JSContext* aCx, JS::MutableHandle<JS::Value> aVal) {
   return DecodeJSValInternal(aPos, aEnd, aCx, 0, aVal, 0);
 }
 
 // static
-template <typename T>
-uint32_t Key::CalcDecodedStringySize(
-    const EncodedDataType* const aBegin, const EncodedDataType* const aEnd,
-    const EncodedDataType** aOutEncodedSectionEnd) {
-  static_assert(sizeof(T) <= 2,
-                "Only implemented for 1 and 2 byte decoded types");
-  uint32_t decodedSize = 0;
-  auto* iter = aBegin;
-  for (; iter < aEnd && *iter != eTerminator; ++iter) {
-    if (*iter & 0x80) {
-      iter += (sizeof(T) > 1 && (*iter & 0x40)) ? 2 : 1;
-    }
-    ++decodedSize;
-  }
-  *aOutEncodedSectionEnd = std::min(aEnd, iter);
-  return decodedSize;
-}
+void Key::DecodeString(const unsigned char*& aPos, const unsigned char* aEnd,
+                       nsString& aString) {
+  NS_ASSERTION(*aPos % eMaxType == eString, "Don't call me!");
+
+  const unsigned char* buffer = aPos + 1;
 
-// static
-template <typename T>
-void Key::DecodeAsStringy(const EncodedDataType* const aEncodedSectionBegin,
-                          const EncodedDataType* const aEncodedSectionEnd,
-                          const uint32_t aDecodedLength, T* const aOut) {
-  static_assert(sizeof(T) <= 2,
-                "Only implemented for 1 and 2 byte decoded types");
-  T* decodedPos = aOut;
-  for (const EncodedDataType* iter = aEncodedSectionBegin;
-       iter < aEncodedSectionEnd;) {
-    if (!(*iter & 0x80)) {
-      *decodedPos = *(iter++) - ONE_BYTE_ADJUST;
-    } else if (sizeof(T) == 1 || !(*iter & 0x40)) {
-      auto c = static_cast<uint16_t>(*(iter++)) << 8;
-      if (iter < aEncodedSectionEnd) {
-        c |= *(iter++);
-      }
-      *decodedPos = static_cast<T>(c - TWO_BYTE_ADJUST - 0x8000);
-    } else if (sizeof(T) > 1) {
-      auto c = static_cast<uint32_t>(*(iter++)) << (16 - THREE_BYTE_SHIFT);
-      if (iter < aEncodedSectionEnd) {
-        c |= static_cast<uint32_t>(*(iter++)) << (8 - THREE_BYTE_SHIFT);
-      }
-      if (iter < aEncodedSectionEnd) {
-        c |= *(iter++) >> THREE_BYTE_SHIFT;
-      }
-      *decodedPos = static_cast<T>(c);
+  // First measure how big the decoded string will be.
+  uint32_t size = 0;
+  const unsigned char* iter;
+  for (iter = buffer; iter < aEnd && *iter != eTerminator; ++iter) {
+    if (*iter & 0x80) {
+      iter += (*iter & 0x40) ? 2 : 1;
     }
-    ++decodedPos;
+    ++size;
   }
 
-  MOZ_ASSERT(static_cast<uint32_t>(decodedPos - aOut) == aDecodedLength,
-             "Should have written the whole decoded area");
-}
+  // Set end so that we don't have to check for null termination in the loop
+  // below
+  if (iter < aEnd) {
+    aEnd = iter;
+  }
 
-// static
-template <Key::EncodedDataType TypeMask, typename T, typename AcquireBuffer,
-          typename AcquireEmpty>
-void Key::DecodeStringy(const EncodedDataType*& aPos,
-                        const EncodedDataType* aEnd,
-                        const AcquireBuffer& acquireBuffer,
-                        const AcquireEmpty& acquireEmpty) {
-  NS_ASSERTION(*aPos % eMaxType == TypeMask, "Don't call me!");
-
-  // First measure how big the decoded stringy data will be.
-  const EncodedDataType* const encodedSectionBegin = aPos + 1;
-  const EncodedDataType* encodedSectionEnd;
-  // decodedLength does not include the terminating 0 (in case of a string)
-  const uint32_t decodedLength =
-      CalcDecodedStringySize<T>(encodedSectionBegin, aEnd, &encodedSectionEnd);
-  aPos = encodedSectionEnd + 1;
-
-  if (!decodedLength) {
-    acquireEmpty();
+  char16_t* out;
+  if (size && !aString.GetMutableData(&out, size)) {
     return;
   }
 
-  T* out;
-  if (!acquireBuffer(&out, decodedLength)) {
-    return;
+  for (iter = buffer; iter < aEnd;) {
+    if (!(*iter & 0x80)) {
+      *out = *(iter++) - ONE_BYTE_ADJUST;
+    } else if (!(*iter & 0x40)) {
+      char16_t c = (char16_t(*(iter++)) << 8);
+      if (iter < aEnd) {
+        c |= *(iter++);
+      }
+      *out = c - TWO_BYTE_ADJUST - 0x8000;
+    } else {
+      uint32_t c = uint32_t(*(iter++)) << (16 - THREE_BYTE_SHIFT);
+      if (iter < aEnd) {
+        c |= uint32_t(*(iter++)) << (8 - THREE_BYTE_SHIFT);
+      }
+      if (iter < aEnd) {
+        c |= *(iter++) >> THREE_BYTE_SHIFT;
+      }
+      *out = (char16_t)c;
+    }
+
+    ++out;
   }
 
-  DecodeAsStringy(encodedSectionBegin, encodedSectionEnd, decodedLength, out);
-}
+  NS_ASSERTION(!size || out == aString.EndReading(),
+               "Should have written the whole string");
 
-// static
-void Key::DecodeString(const EncodedDataType*& aPos,
-                       const EncodedDataType* const aEnd, nsString& aString) {
-  MOZ_ASSERT(aString.IsEmpty(), "aString should be empty on call!");
-
-  DecodeStringy<eString, char16_t>(
-      aPos, aEnd,
-      [&aString](char16_t** out, uint32_t decodedLength) {
-        return 0 != aString.GetMutableData(out, decodedLength);
-      },
-      [] {});
+  aPos = iter + 1;
 }
 
 void Key::EncodeNumber(double aFloat, uint8_t aType) {
   // Allocate memory for the new size
   uint32_t oldLen = mBuffer.Length();
   char* buffer;
   if (!mBuffer.GetMutableData(&buffer, oldLen + 1 + sizeof(double))) {
     return;
@@ -724,18 +687,18 @@ void Key::EncodeNumber(double aFloat, ui
   // MSVC build warning C4146 (negating an unsigned value).
   const uint64_t signbit = FloatingPoint<double>::kSignBit;
   uint64_t number = bits & signbit ? (0 - bits) : (bits | signbit);
 
   mozilla::BigEndian::writeUint64(buffer, number);
 }
 
 // static
-double Key::DecodeNumber(const EncodedDataType*& aPos,
-                         const EncodedDataType* aEnd) {
+double Key::DecodeNumber(const unsigned char*& aPos,
+                         const unsigned char* aEnd) {
   NS_ASSERTION(*aPos % eMaxType == eFloat || *aPos % eMaxType == eDate,
                "Don't call me!");
 
   ++aPos;
 
   uint64_t number = 0;
   memcpy(&number, aPos, std::min<size_t>(sizeof(number), aEnd - aPos));
   number = mozilla::NativeEndian::swapFromBigEndian(number);
@@ -770,32 +733,69 @@ IDBResult<void, IDBSpecialValue::Invalid
                                     &bufferData);
   }
 
   return EncodeAsString(bufferData, bufferData + bufferLength,
                         eBinary + aTypeOffset, aRv);
 }
 
 // static
-JSObject* Key::DecodeBinary(const EncodedDataType*& aPos,
-                            const EncodedDataType* aEnd, JSContext* aCx) {
-  JSObject* rv;
-  DecodeStringy<eBinary, uint8_t>(
-      aPos, aEnd,
-      [&rv, aCx](uint8_t** out, uint32_t decodedSize) {
-        *out = static_cast<uint8_t*>(JS_malloc(aCx, decodedSize));
-        if (NS_WARN_IF(!*out)) {
-          rv = nullptr;
-          return false;
-        }
-        rv = JS::NewArrayBufferWithContents(aCx, decodedSize, *out);
-        return true;
-      },
-      [&rv, aCx] { rv = JS::NewArrayBuffer(aCx, 0); });
-  return rv;
+JSObject* Key::DecodeBinary(const unsigned char*& aPos,
+                            const unsigned char* aEnd, JSContext* aCx) {
+  MOZ_ASSERT(*aPos % eMaxType == eBinary, "Don't call me!");
+
+  const unsigned char* buffer = ++aPos;
+
+  // First measure how big the decoded array buffer will be.
+  size_t size = 0;
+  const unsigned char* iter;
+  for (iter = buffer; iter < aEnd && *iter != eTerminator; ++iter) {
+    if (*iter & 0x80) {
+      iter++;
+    }
+    ++size;
+  }
+
+  if (!size) {
+    return JS::NewArrayBuffer(aCx, 0);
+  }
+
+  uint8_t* out = static_cast<uint8_t*>(JS_malloc(aCx, size));
+  if (NS_WARN_IF(!out)) {
+    return nullptr;
+  }
+
+  uint8_t* pos = out;
+
+  // Set end so that we don't have to check for null termination in the loop
+  // below
+  if (iter < aEnd) {
+    aEnd = iter;
+  }
+
+  for (iter = buffer; iter < aEnd;) {
+    if (!(*iter & 0x80)) {
+      *pos = *(iter++) - ONE_BYTE_ADJUST;
+    } else {
+      uint16_t c = (uint16_t(*(iter++)) << 8);
+      if (iter < aEnd) {
+        c |= *(iter++);
+      }
+      *pos = static_cast<uint8_t>(c - TWO_BYTE_ADJUST - 0x8000);
+    }
+
+    ++pos;
+  }
+
+  aPos = iter + 1;
+
+  MOZ_ASSERT(static_cast<size_t>(pos - out) == size,
+             "Should have written the whole buffer");
+
+  return JS::NewArrayBufferWithContents(aCx, size, out);
 }
 
 nsresult Key::BindToStatement(mozIStorageStatement* aStatement,
                               const nsACString& aParamName) const {
   nsresult rv;
   if (IsUnset()) {
     rv = aStatement->BindNullByName(aParamName);
   } else {
@@ -836,17 +836,17 @@ IDBResult<void, IDBSpecialValue::Invalid
 }
 
 nsresult Key::ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const {
   if (IsUnset()) {
     aVal.setUndefined();
     return NS_OK;
   }
 
-  const EncodedDataType* pos = BufferStart();
+  const unsigned char* pos = BufferStart();
   nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, aVal);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   MOZ_ASSERT(pos >= BufferEnd());
 
   return NS_OK;
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -103,33 +103,33 @@ class Key {
   bool IsString() const { return !IsUnset() && *BufferStart() == eString; }
 
   bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary; }
 
   bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray; }
 
   double ToFloat() const {
     Assert(IsFloat());
-    const EncodedDataType* pos = BufferStart();
+    const unsigned char* pos = BufferStart();
     double res = DecodeNumber(pos, BufferEnd());
     Assert(pos >= BufferEnd());
     return res;
   }
 
   double ToDateMsec() const {
     Assert(IsDate());
-    const EncodedDataType* pos = BufferStart();
+    const unsigned char* pos = BufferStart();
     double res = DecodeNumber(pos, BufferEnd());
     Assert(pos >= BufferEnd());
     return res;
   }
 
   void ToString(nsString& aString) const {
     Assert(IsString());
-    const EncodedDataType* pos = BufferStart();
+    const unsigned char* pos = BufferStart();
     DecodeString(pos, BufferEnd(), aString);
     Assert(pos >= BufferEnd());
   }
 
   IDBResult<void, IDBSpecialValue::Invalid> SetFromString(
       const nsAString& aString, ErrorResult& aRv);
 
   void SetFromInteger(int64_t aInt) {
@@ -247,25 +247,22 @@ class Key {
     // 6. Return a new array key with value `keys`.
     aPolicy.EndSubkeyList();
     return Ok();
   }
 
  private:
   class MOZ_STACK_CLASS ArrayValueEncoder;
 
-  using EncodedDataType = unsigned char;
-
-  const EncodedDataType* BufferStart() const {
-    // TODO it would be nicer if mBuffer was also using EncodedDataType
-    return reinterpret_cast<const EncodedDataType*>(mBuffer.BeginReading());
+  const unsigned char* BufferStart() const {
+    return reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
   }
 
-  const EncodedDataType* BufferEnd() const {
-    return reinterpret_cast<const EncodedDataType*>(mBuffer.EndReading());
+  const unsigned char* BufferEnd() const {
+    return reinterpret_cast<const unsigned char*>(mBuffer.EndReading());
   }
 
   // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
   // step.
   void TrimBuffer() {
     const char* end = mBuffer.EndReading() - 1;
     while (!*end) {
       --end;
@@ -301,62 +298,37 @@ class Key {
   void EncodeNumber(double aFloat, uint8_t aType);
 
   IDBResult<void, IDBSpecialValue::Invalid> EncodeBinary(JSObject* aObject,
                                                          bool aIsViewObject,
                                                          uint8_t aTypeOffset,
                                                          ErrorResult& aRv);
 
   // Decoding functions. aPos points into mBuffer and is adjusted to point
-  // past the consumed value. (Note: this may be beyond aEnd).
-  static nsresult DecodeJSVal(const EncodedDataType*& aPos,
-                              const EncodedDataType* aEnd, JSContext* aCx,
+  // past the consumed value.
+  static nsresult DecodeJSVal(const unsigned char*& aPos,
+                              const unsigned char* aEnd, JSContext* aCx,
                               JS::MutableHandle<JS::Value> aVal);
 
-  static void DecodeString(const EncodedDataType*& aPos,
-                           const EncodedDataType* aEnd, nsString& aString);
-
-  static double DecodeNumber(const EncodedDataType*& aPos,
-                             const EncodedDataType* aEnd);
-
-  static JSObject* DecodeBinary(const EncodedDataType*& aPos,
-                                const EncodedDataType* aEnd, JSContext* aCx);
+  static void DecodeString(const unsigned char*& aPos,
+                           const unsigned char* aEnd, nsString& aString);
 
-  // Returns the size of the decoded data for stringy (string or binary),
-  // excluding a null terminator.
-  // On return, aOutSectionEnd points to the last byte behind the current
-  // encoded section, i.e. either aEnd, or the eTerminator.
-  // T is the base type for the decoded data.
-  template <typename T>
-  static uint32_t CalcDecodedStringySize(
-      const EncodedDataType* aBegin, const EncodedDataType* aEnd,
-      const EncodedDataType** aOutEncodedSectionEnd);
+  static double DecodeNumber(const unsigned char*& aPos,
+                             const unsigned char* aEnd);
 
-  static uint32_t LengthOfEncodedBinary(const EncodedDataType* aPos,
-                                        const EncodedDataType* aEnd);
-
-  template <typename T>
-  static void DecodeAsStringy(const EncodedDataType* aEncodedSectionBegin,
-                              const EncodedDataType* aEncodedSectionEnd,
-                              uint32_t aDecodedLength, T* aOut);
-
-  template <EncodedDataType TypeMask, typename T, typename AcquireBuffer,
-            typename AcquireEmpty>
-  static void DecodeStringy(const EncodedDataType*& aPos,
-                            const EncodedDataType* aEnd,
-                            const AcquireBuffer& acquireBuffer,
-                            const AcquireEmpty& acquireEmpty);
+  static JSObject* DecodeBinary(const unsigned char*& aPos,
+                                const unsigned char* aEnd, JSContext* aCx);
 
   IDBResult<void, IDBSpecialValue::Invalid> EncodeJSValInternal(
       JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset,
       uint16_t aRecursionDepth, ErrorResult& aRv);
 
-  static nsresult DecodeJSValInternal(const EncodedDataType*& aPos,
-                                      const EncodedDataType* aEnd,
-                                      JSContext* aCx, uint8_t aTypeOffset,
+  static nsresult DecodeJSValInternal(const unsigned char*& aPos,
+                                      const unsigned char* aEnd, JSContext* aCx,
+                                      uint8_t aTypeOffset,
                                       JS::MutableHandle<JS::Value> aVal,
                                       uint16_t aRecursionDepth);
 
   template <typename T>
   nsresult SetFromSource(T* aSource, uint32_t aIndex);
 
   void Assert(bool aCondition) const
 #ifdef DEBUG
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -267,32 +267,16 @@ function compareKeys(_k1_, _k2_) {
       if (!compareKeys(_k1_[i], _k2_[i])) {
         return false;
       }
     }
 
     return true;
   }
 
-  if (_k1_ instanceof ArrayBuffer) {
-    if (!(_k2_ instanceof ArrayBuffer)) {
-      return false;
-    }
-
-    function arrayBuffersAreEqual(a, b) {
-      if (a.byteLength != b.byteLength) {
-        return false;
-      }
-      let ui8b = new Uint8Array(b);
-      return new Uint8Array(a).every((val, i) => val === ui8b[i]);
-    }
-
-    return arrayBuffersAreEqual(_k1_, _k2_);
-  }
-
   return false;
 }
 
 function removePermission(type, url) {
   if (!url) {
     url = window.document;
   }
   SpecialPowers.removePermission(type, url);
@@ -496,18 +480,16 @@ function workerScript() {
       if (this._preventDefault) {
         _event_.preventDefault();
         _event_.stopPropagation();
       }
       grabEventAndContinueHandler(_event_);
     },
   };
 
-  // TODO this is duplicate from the global compareKeys function defined above,
-  // this duplication should be avoided (bug 1565986)
   self.compareKeys = function(_k1_, _k2_) {
     let t = typeof _k1_;
     if (t != typeof _k2_) {
       return false;
     }
 
     if (t !== "object") {
       return _k1_ === _k2_;
@@ -526,32 +508,16 @@ function workerScript() {
         if (!compareKeys(_k1_[i], _k2_[i])) {
           return false;
         }
       }
 
       return true;
     }
 
-    if (_k1_ instanceof ArrayBuffer) {
-      if (!(_k2_ instanceof ArrayBuffer)) {
-        return false;
-      }
-
-      function arrayBuffersAreEqual(a, b) {
-        if (a.byteLength != b.byteLength) {
-          return false;
-        }
-        let ui8b = new Uint8Array(b);
-        return new Uint8Array(a).every((val, i) => val === ui8b[i]);
-      }
-
-      return arrayBuffersAreEqual(_k1_, _k2_);
-    }
-
     return false;
   };
 
   self.getRandomBuffer = function(_size_) {
     let buffer = new ArrayBuffer(_size_);
     is(buffer.byteLength, _size_, "Correct byte length");
     let view = new Uint8Array(buffer);
     for (let i = 0; i < _size_; i++) {
--- a/dom/indexedDB/test/unit/test_keys.js
+++ b/dom/indexedDB/test/unit/test_keys.js
@@ -1,44 +1,29 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var testGenerator = testSteps();
 
-// helper function that ensures that ArrayBuffer instances are meaningfully
-// displayed (not just as 'object ArrayBuffer')
-// TODO better move to helpers.js?
-function showKey(key) {
-  if (key instanceof Array) {
-    return key.map(x => showKey(x)).toString();
-  }
-  if (key instanceof ArrayBuffer) {
-    return "ArrayBuffer([" + new Uint8Array(key).toString() + "])";
-  }
-  return key.toString();
-}
-
 function* testSteps() {
   const dbname = this.window ? window.location.pathname : "Splendid Test";
 
   let openRequest = indexedDB.open(dbname, 1);
   openRequest.onerror = errorHandler;
   openRequest.onupgradeneeded = grabEventAndContinueHandler;
   openRequest.onsuccess = unexpectedSuccessHandler;
   let event = yield undefined;
   let db = event.target.result;
 
   // Create test stores
   let store = db.createObjectStore("store");
-  let enc = new TextEncoder();
 
   // Test simple inserts
-  // Note: the keys must be in order
   var keys = [
     -1 / 0,
     -1.7e308,
     -10000,
     -2,
     -1.5,
     -1,
     -1.00001e-200,
@@ -117,30 +102,16 @@ function* testSteps() {
     "\uD800\uDC01",
     "\uDBFF",
     "\uDC00",
     "\uDFFF\uD800",
     "\uFFFE",
     "\uFFFF",
     "\uFFFF\x00",
     "\uFFFFZZZ",
-    // Note: enc.encode returns an Uint8Array, which is a valid key, but when
-    // converting it back and forth, the result will be a plain ArrayBuffer,
-    // which is expected in comparisons below
-    // TODO is it ok that the information that the original key was an
-    // Uint8Array is lost?
-    new ArrayBuffer(0),
-    Uint8Array.from([0]).buffer,
-    Uint8Array.from([0, 0]).buffer,
-    Uint8Array.from([0, 1]).buffer,
-    Uint8Array.from([0, 1, 0]).buffer,
-    enc.encode("abc").buffer,
-    enc.encode("abcd").buffer,
-    enc.encode("xyz").buffer,
-    Uint8Array.from([0x80]).buffer,
     [],
     [-1 / 0],
     [-1],
     [0],
     [1],
     [1, "a"],
     [1, []],
     [1, [""]],
@@ -160,25 +131,16 @@ function* testSteps() {
     ["abc"],
     ["abc", "def"],
     ["abc\x00"],
     ["abc\x00", "\x00\x01"],
     ["abc\x00", "\x00def"],
     ["abc\x00\x00def"],
     ["x", [[]]],
     ["x", [[[]]]],
-    // see comment on scalar ArrayBuffers above
-    [new ArrayBuffer(0)],
-    [new ArrayBuffer(0), "abc"],
-    [new ArrayBuffer(0), new ArrayBuffer(0)],
-    [new ArrayBuffer(0), enc.encode("abc").buffer],
-    [enc.encode("abc").buffer],
-    [enc.encode("abc").buffer, new ArrayBuffer(0)],
-    [enc.encode("abc").buffer, enc.encode("xyz").buffer],
-    [enc.encode("xyz").buffer],
     [[]],
     [[], "foo"],
     [[], []],
     [[[]]],
     [[[]], []],
     [[[]], [[]]],
     [[[]], [[1]]],
     [[[]], [[[]]]],
@@ -197,31 +159,21 @@ function* testSteps() {
       }
     }
 
     doCompare(keyI);
     store.add(i, keyI).onsuccess = function(e) {
       is(
         indexedDB.cmp(e.target.result, keyI),
         0,
-        "Returned key should cmp as equal; index = " +
-          i +
-          ", input = " +
-          showKey(keyI) +
-          ", returned = " +
-          showKey(e.target.result)
+        "Returned key should cmp as equal"
       );
       ok(
         compareKeys(e.target.result, keyI),
-        "Returned key should actually be equal; index = " +
-          i +
-          ", input = " +
-          showKey(keyI) +
-          ", returned = " +
-          showKey(e.target.result)
+        "Returned key should actually be equal"
       );
     };
 
     // Test that -0 compares the same as 0
     if (keyI === 0) {
       doCompare(-0);
       let req = store.add(i, -0);
       req.addEventListener("error", new ExpectError("ConstraintError", true));
@@ -238,31 +190,21 @@ function* testSteps() {
 
   store.openCursor().onsuccess = grabEventAndContinueHandler;
   for (i = 0; i < keys.length; ++i) {
     event = yield undefined;
     let cursor = event.target.result;
     is(
       indexedDB.cmp(cursor.key, keys[i]),
       0,
-      "Read back key should cmp as equal; index = " +
-        i +
-        ", input = " +
-        showKey(keys[i]) +
-        ", readBack = " +
-        showKey(cursor.key)
+      "Read back key should cmp as equal"
     );
     ok(
       compareKeys(cursor.key, keys[i]),
-      "Read back key should actually be equal; index = " +
-        i +
-        ", input = " +
-        showKey(keys[i]) +
-        ", readBack = " +
-        showKey(cursor.key)
+      "Read back key should actually be equal"
     );
     is(cursor.value, i, "Stored with right value");
 
     cursor.continue();
   }
   event = yield undefined;
   is(event.target.result, null, "no more results expected");
 
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -145,19 +145,16 @@ ExpectError.prototype = {
     grabEventAndContinueHandler(event);
   },
 };
 
 function continueToNextStepSync() {
   testGenerator.next();
 }
 
-// TODO compareKeys is duplicated in ../helpers.js, can we import that here?
-// the same applies to many other functions in this file
-// this duplication should be avoided (bug 1565986)
 function compareKeys(k1, k2) {
   let t = typeof k1;
   if (t != typeof k2) {
     return false;
   }
 
   if (t !== "object") {
     return k1 === k2;
@@ -176,32 +173,16 @@ function compareKeys(k1, k2) {
       if (!compareKeys(k1[i], k2[i])) {
         return false;
       }
     }
 
     return true;
   }
 
-  if (k1 instanceof ArrayBuffer) {
-    if (!(k2 instanceof ArrayBuffer)) {
-      return false;
-    }
-
-    function arrayBuffersAreEqual(a, b) {
-      if (a.byteLength != b.byteLength) {
-        return false;
-      }
-      let ui8b = new Uint8Array(b);
-      return new Uint8Array(a).every((val, i) => val === ui8b[i]);
-    }
-
-    return arrayBuffersAreEqual(k1, k2);
-  }
-
   return false;
 }
 
 function addPermission(permission, url) {
   throw new Error("addPermission");
 }
 
 function removePermission(permission, url) {