Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Tue, 05 Mar 2019 11:27:18 +0200
changeset 520224 78601cacfe69dc8659c3fe7cd3eb94366aa3d680
parent 520216 0c4c0810b93fa8fb8c8f1439b78ced96ba91450f (current diff)
parent 520223 ffd3366e43f3e7fed749596dfacdb366d38e61ca (diff)
child 520231 79221722fcc6b17019ed84227deb02e85f4bf1e2
child 520274 2d7395290c187ee80403a08267ea8c26eca2df8c
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
78601cacfe69 / 67.0a1 / 20190305092747 / files
nightly linux64
78601cacfe69 / 67.0a1 / 20190305092747 / files
nightly mac
78601cacfe69 / 67.0a1 / 20190305092747 / files
nightly win32
78601cacfe69 / 67.0a1 / 20190305092747 / files
nightly win64
78601cacfe69 / 67.0a1 / 20190305092747 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
--- a/dom/base/BodyUtil.cpp
+++ b/dom/base/BodyUtil.cpp
@@ -13,16 +13,17 @@
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsDOMString.h"
 #include "nsNetUtil.h"
 #include "nsReadableUtils.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 
+#include "js/ArrayBuffer.h"  // JS::NewArrayBufferWithContents
 #include "js/JSON.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/Promise.h"
@@ -381,18 +382,18 @@ class MOZ_STACK_CLASS FormDataParser {
 }  // namespace
 
 // static
 void BodyUtil::ConsumeArrayBuffer(JSContext* aCx,
                                   JS::MutableHandle<JSObject*> aValue,
                                   uint32_t aInputLength, uint8_t* aInput,
                                   ErrorResult& aRv) {
   JS::Rooted<JSObject*> arrayBuffer(aCx);
-  arrayBuffer = JS_NewArrayBufferWithContents(aCx, aInputLength,
-                                              reinterpret_cast<void*>(aInput));
+  arrayBuffer = JS::NewArrayBufferWithContents(aCx, aInputLength,
+                                               reinterpret_cast<void*>(aInput));
   if (!arrayBuffer) {
     JS_ClearPendingException(aCx);
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
   aValue.set(arrayBuffer);
 }
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -15,16 +15,17 @@
 #include "harfbuzz/hb.h"
 #include "imgICache.h"
 #include "imgIContainer.h"
 #include "imgINotificationObserver.h"
 #include "imgLoader.h"
 #include "imgRequestProxy.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::{GetArrayBufferData,IsArrayBufferObject,NewArrayBuffer}
 #include "js/JSON.h"
 #include "js/Value.h"
 #include "Layers.h"
 #include "nsAppRunner.h"
 // nsNPAPIPluginInstance must be included before mozilla/dom/Document.h, which
 // is included in mozAutoDocUpdate.h.
 #include "nsNPAPIPluginInstance.h"
 #include "gfxDrawable.h"
@@ -6073,26 +6074,26 @@ nsresult nsContentUtils::WrapNative(JSCo
 nsresult nsContentUtils::CreateArrayBuffer(JSContext* aCx,
                                            const nsACString& aData,
                                            JSObject** aResult) {
   if (!aCx) {
     return NS_ERROR_FAILURE;
   }
 
   int32_t dataLen = aData.Length();
-  *aResult = JS_NewArrayBuffer(aCx, dataLen);
+  *aResult = JS::NewArrayBuffer(aCx, dataLen);
   if (!*aResult) {
     return NS_ERROR_FAILURE;
   }
 
   if (dataLen > 0) {
-    NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
+    NS_ASSERTION(JS::IsArrayBufferObject(*aResult), "What happened?");
     JS::AutoCheckCannotGC nogc;
     bool isShared;
-    memcpy(JS_GetArrayBufferData(*aResult, &isShared, nogc),
+    memcpy(JS::GetArrayBufferData(*aResult, &isShared, nogc),
            aData.BeginReading(), dataLen);
     MOZ_ASSERT(!isShared);
   }
 
   return NS_OK;
 }
 
 void nsContentUtils::StripNullChars(const nsAString& aInStr,
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -2,16 +2,21 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_TypedArray_h
 #define mozilla_dom_TypedArray_h
 
+#include "jsfriendapi.h"  // js::Scalar
+#include "js/ArrayBuffer.h"
+#include "js/SharedArrayBuffer.h"
+#include "js/GCAPI.h"       // JS::AutoCheckCannotGC
+#include "js/RootingAPI.h"  // JS::Rooted
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/SpiderMonkeyInterface.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
@@ -67,17 +72,17 @@ struct TypedArray_base : public SpiderMo
   //
   // Two methods are available for determining if a DOM view maps
   // shared memory.  The IsShared() method is cheap and can be called
   // if the view has been computed; the JS_GetTypedArraySharedness()
   // method is slightly more expensive and can be called on the Obj()
   // value if the view may not have been computed and if the value is
   // known to represent a JS TypedArray.
   //
-  // (Just use JS_IsSharedArrayBuffer() to test if any object is of
+  // (Just use JS::IsSharedArrayBuffer() to test if any object is of
   // that type.)
   //
   // Code that elects to allow views that map shared memory to be used
   // -- ie, code that "opts in to shared memory" -- should generally
   // not access the raw data buffer with standard C++ mechanisms as
   // that creates the possibility of C++ data races, which is
   // undefined behavior.  The JS engine will eventually export (bug
   // 1225033) a suite of methods that avoid undefined behavior.
@@ -252,23 +257,23 @@ typedef TypedArray<float, js::UnwrapFloa
     Float32Array;
 typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData,
                    js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
     Float64Array;
 typedef ArrayBufferView_base<js::UnwrapArrayBufferView,
                              js::GetArrayBufferViewLengthAndData,
                              JS_GetArrayBufferViewType>
     ArrayBufferView;
-typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
-                   js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
+typedef TypedArray<uint8_t, JS::UnwrapArrayBuffer, JS::GetArrayBufferData,
+                   JS::GetArrayBufferLengthAndData, JS::NewArrayBuffer>
     ArrayBuffer;
 
 typedef TypedArray<
-    uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
-    js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
+    uint8_t, JS::UnwrapSharedArrayBuffer, JS::GetSharedArrayBufferData,
+    JS::GetSharedArrayBufferLengthAndData, JS::NewSharedArrayBuffer>
     SharedArrayBuffer;
 
 // A class for converting an nsTArray to a TypedArray
 // Note: A TypedArrayCreator must not outlive the nsTArray it was created from.
 //       So this is best used to pass from things that understand nsTArray to
 //       things that understand TypedArray, as with ToJSValue.
 template <typename TypedArrayType>
 class TypedArrayCreator {
--- a/dom/file/FileReader.cpp
+++ b/dom/file/FileReader.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FileReader.h"
 
 #include "nsIEventTarget.h"
 #include "nsIGlobalObject.h"
 #include "nsITimer.h"
 
+#include "js/ArrayBuffer.h"  // JS::NewArrayBufferWithContents
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileReaderBinding.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "mozilla/dom/WorkerCommon.h"
@@ -175,17 +176,17 @@ void FileReader::OnLoadEndArrayBuffer() 
     FreeDataAndDispatchError(NS_ERROR_FAILURE);
     return;
   }
 
   RootResultArrayBuffer();
 
   JSContext* cx = jsapi.cx();
 
-  mResultArrayBuffer = JS_NewArrayBufferWithContents(cx, mDataLen, mFileData);
+  mResultArrayBuffer = JS::NewArrayBufferWithContents(cx, mDataLen, mFileData);
   if (mResultArrayBuffer) {
     mFileData = nullptr;  // Transfer ownership
     FreeDataAndDispatchSuccess();
     return;
   }
 
   // Let's handle the error status.
 
--- a/dom/file/FileReaderSync.cpp
+++ b/dom/file/FileReaderSync.cpp
@@ -1,17 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "FileReaderSync.h"
 
-#include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::NewArrayBufferWithContents
+#include "js/RootingAPI.h"   // JS::{,Mutable}Handle
+#include "js/Utility.h"  // js::ArrayBufferContentsArena, JS::FreePolicy, js_pod_arena_malloc
 #include "mozilla/Unused.h"
 #include "mozilla/Base64.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/dom/FileReaderSyncBinding.h"
 #include "nsCExternalHandlerService.h"
 #include "nsComponentManagerUtils.h"
 #include "nsCOMPtr.h"
@@ -78,17 +80,17 @@ void FileReaderSync::ReadAsArrayBuffer(J
 
   // The file is changed in the meantime?
   if (numRead != blobSize) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   JSObject* arrayBuffer =
-      JS_NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
+      JS::NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
   if (!arrayBuffer) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
   // arrayBuffer takes the ownership when it is not null. Otherwise we
   // need to release it explicitly.
   mozilla::Unused << bufferData.release();
 
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -4,16 +4,17 @@
  * 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 "Key.h"
 
 #include <algorithm>
 #include <stdint.h>  // for UINT32_MAX, uintptr_t
 #include "IndexedDatabaseManager.h"
+#include "js/ArrayBuffer.h"  // JS::{IsArrayBufferObject,NewArrayBuffer{,WithContents},GetArrayBufferLengthAndData}
 #include "js/Date.h"
 #include "js/MemoryFunctions.h"
 #include "js/Value.h"
 #include "jsfriendapi.h"
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/FloatingPoint.h"
@@ -291,17 +292,17 @@ nsresult Key::EncodeJSValInternal(JSCont
       if (!js::DateGetMsecSinceEpoch(aCx, obj, &t)) {
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
       EncodeNumber(t, eDate + aTypeOffset);
       return NS_OK;
     }
 
-    if (JS_IsArrayBufferObject(obj)) {
+    if (JS::IsArrayBufferObject(obj)) {
       return EncodeBinary(obj, /* aIsViewObject */ false, aTypeOffset);
     }
 
     if (JS_IsArrayBufferViewObject(obj)) {
       return EncodeBinary(obj, /* aIsViewObject */ true, aTypeOffset);
     }
   }
 
@@ -630,17 +631,17 @@ nsresult Key::EncodeBinary(JSObject* aOb
   uint8_t* bufferData;
   uint32_t bufferLength;
   bool unused;
 
   if (aIsViewObject) {
     js::GetArrayBufferViewLengthAndData(aObject, &bufferLength, &unused,
                                         &bufferData);
   } else {
-    js::GetArrayBufferLengthAndData(aObject, &bufferLength, &unused,
+    JS::GetArrayBufferLengthAndData(aObject, &bufferLength, &unused,
                                     &bufferData);
   }
 
   return EncodeAsString(bufferData, bufferData + bufferLength,
                         eBinary + aTypeOffset);
 }
 
 // static
@@ -656,17 +657,17 @@ JSObject* Key::DecodeBinary(const unsign
   for (iter = buffer; iter < aEnd && *iter != eTerminator; ++iter) {
     if (*iter & 0x80) {
       iter++;
     }
     ++size;
   }
 
   if (!size) {
-    return JS_NewArrayBuffer(aCx, 0);
+    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;
@@ -691,17 +692,17 @@ JSObject* Key::DecodeBinary(const unsign
     ++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);
+  return JS::NewArrayBufferWithContents(aCx, size, out);
 }
 
 nsresult Key::BindToStatement(mozIStorageStatement* aStatement,
                               const nsACString& aParamName) const {
   nsresult rv;
   if (IsUnset()) {
     rv = aStatement->BindNullByName(aParamName);
   } else {
--- a/dom/media/webaudio/AudioBuffer.cpp
+++ b/dom/media/webaudio/AudioBuffer.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioBuffer.h"
 #include "mozilla/dom/AudioBufferBinding.h"
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::StealArrayBufferContents
 #include "mozilla/ErrorResult.h"
 #include "AudioSegment.h"
 #include "AudioChannelFormat.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/MemoryReporting.h"
 #include "AudioNodeEngine.h"
 
@@ -421,17 +422,17 @@ AudioBuffer::StealJSArrayDataIntoSharedC
     bool isSharedMemory;
     JS::Rooted<JSObject*> arrayBuffer(
         aJSContext, JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView,
                                                 &isSharedMemory));
     // The channel data arrays should all have originated in
     // RestoreJSChannelData, where they are created unshared.
     MOZ_ASSERT(!isSharedMemory);
     auto stolenData = arrayBuffer
-                          ? static_cast<float*>(JS_StealArrayBufferContents(
+                          ? static_cast<float*>(JS::StealArrayBufferContents(
                                 aJSContext, arrayBuffer))
                           : nullptr;
     if (stolenData) {
       result->SetData(i, stolenData, js_free, stolenData);
     } else {
       NS_ASSERTION(i == 0, "some channels lost when contents not acquired");
       return nullptr;
     }
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -53,16 +53,17 @@
 #include "ChannelMergerNode.h"
 #include "ChannelSplitterNode.h"
 #include "ConstantSourceNode.h"
 #include "ConvolverNode.h"
 #include "DelayNode.h"
 #include "DynamicsCompressorNode.h"
 #include "GainNode.h"
 #include "IIRFilterNode.h"
+#include "js/ArrayBuffer.h"  // JS::StealArrayBufferContents
 #include "MediaElementAudioSourceNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "MediaStreamAudioSourceNode.h"
 #include "MediaStreamGraph.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
@@ -579,17 +580,17 @@ already_AddRefed<Promise> AudioContext::
     aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_DETACHED>(
         NS_LITERAL_STRING("Argument of AudioContext.decodeAudioData"));
     return nullptr;
   }
 
   // Detach the array buffer
   size_t length = aBuffer.Length();
 
-  uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
+  uint8_t* data = static_cast<uint8_t*>(JS::StealArrayBufferContents(cx, obj));
 
   // Sniff the content of the media.
   // Failed type sniffing will be handled by AsyncDecodeWebAudio.
   nsAutoCString contentType;
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
 
   RefPtr<DecodeErrorCallback> failureCallback;
   RefPtr<DecodeSuccessCallback> successCallback;
--- a/dom/media/webaudio/AudioNodeEngine.h
+++ b/dom/media/webaudio/AudioNodeEngine.h
@@ -35,17 +35,17 @@ class ThreadSharedFloatArrayBufferList f
   /**
    * Construct with null channel data pointers.
    */
   explicit ThreadSharedFloatArrayBufferList(uint32_t aCount) {
     mContents.SetLength(aCount);
   }
   /**
    * Create with buffers suitable for transfer to
-   * JS_NewArrayBufferWithContents().  The buffer contents are uninitialized
+   * JS::NewArrayBufferWithContents().  The buffer contents are uninitialized
    * and so should be set using GetDataForWrite().
    */
   static already_AddRefed<ThreadSharedFloatArrayBufferList> Create(
       uint32_t aChannelCount, size_t aLength, const mozilla::fallible_t&);
 
   ThreadSharedFloatArrayBufferList* AsThreadSharedFloatArrayBufferList()
       override {
     return this;
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -296,17 +296,17 @@ void MediaDecodeTask::FinishDecode() {
   }
 
   // Allocate contiguous channel buffers.  Note that if we end up resampling,
   // we may write fewer bytes than mResampledFrames to the output buffer, in
   // which case writeIndex will tell us how many valid samples we have.
   mDecodeJob.mBuffer.mChannelData.SetLength(channelCount);
 #if AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_FLOAT32
   // This buffer has separate channel arrays that could be transferred to
-  // JS_NewArrayBufferWithContents(), but AudioBuffer::RestoreJSChannelData()
+  // JS::NewArrayBufferWithContents(), but AudioBuffer::RestoreJSChannelData()
   // does not yet take advantage of this.
   RefPtr<ThreadSharedFloatArrayBufferList> buffer =
       ThreadSharedFloatArrayBufferList::Create(channelCount, resampledFrames,
                                                fallible);
   if (!buffer) {
     ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
     return;
   }
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -9,36 +9,38 @@
 #include "mozilla/Unused.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "nsITCPSocketCallback.h"
 #include "TCPSocket.h"
 #include "nsContentUtils.h"
-#include "jsapi.h"
-#include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::NewArrayBufferWithContents
+#include "js/RootingAPI.h"   // JS::MutableHandle
+#include "js/Utility.h"  // js::ArrayBufferContentsArena, JS::FreePolicy, js_pod_arena_malloc
+#include "js/Value.h"  // JS::Value
 
 using mozilla::net::gNeckoChild;
 
 namespace IPC {
 
 bool DeserializeArrayBuffer(JSContext* cx,
                             const InfallibleTArray<uint8_t>& aBuffer,
                             JS::MutableHandle<JS::Value> aVal) {
   mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(
       js_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena,
                                    aBuffer.Length()));
   if (!data) return false;
   memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
 
   JSObject* obj =
-      JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
+      JS::NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
   if (!obj) return false;
-  // If JS_NewArrayBufferWithContents returns non-null, the ownership of
+  // If JS::NewArrayBufferWithContents returns non-null, the ownership of
   // the data is transfered to obj, so we release the ownership here.
   mozilla::Unused << data.release();
 
   aVal.setObject(*obj);
   return true;
 }
 
 }  // namespace IPC
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -2894,16 +2894,18 @@ void ScriptLoader::EncodeRequestBytecode
   LOG((
       "ScriptLoadRequest (%p): Write bytecode cache (rv = %X, length = %u, "
       "written = %u)",
       aRequest, unsigned(rv), unsigned(aRequest->mScriptBytecode.length()), n));
   if (NS_FAILED(rv)) {
     return;
   }
 
+  MOZ_RELEASE_ASSERT(aRequest->mScriptBytecode.length() == n);
+
   bytecodeFailed.release();
   TRACE_FOR_TEST_NONE(aRequest->Element(), "scriptloader_bytecode_saved");
 }
 
 void ScriptLoader::GiveUpBytecodeEncoding() {
   // If the document went away prematurely, we still want to set this, in order
   // to avoid queuing more scripts.
   mGiveUpEncoding = true;
--- a/dom/simpledb/SDBConnection.cpp
+++ b/dom/simpledb/SDBConnection.cpp
@@ -2,17 +2,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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 "SDBConnection.h"
 
 #include "ActorsChild.h"
-#include "jsfriendapi.h"
+#include "jsfriendapi.h"     // JS_GetObjectAsArrayBufferView
+#include "js/ArrayBuffer.h"  // JS::{GetObjectAsArrayBuffer,IsArrayBufferObject}
+#include "js/RootingAPI.h"   // JS::{Handle,Rooted}
+#include "js/Value.h"        // JS::Value
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "nsISDBCallbacks.h"
 #include "SDBRequest.h"
 #include "SimpleDBCommon.h"
 
@@ -24,25 +27,25 @@ using namespace mozilla::ipc;
 namespace {
 
 nsresult GetWriteData(JSContext* aCx, JS::Handle<JS::Value> aValue,
                       nsCString& aData) {
   if (aValue.isObject()) {
     JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
 
     bool isView = false;
-    if (JS_IsArrayBufferObject(obj) ||
+    if (JS::IsArrayBufferObject(obj) ||
         (isView = JS_IsArrayBufferViewObject(obj))) {
       uint8_t* data;
       uint32_t length;
       bool unused;
       if (isView) {
         JS_GetObjectAsArrayBufferView(obj, &length, &unused, &data);
       } else {
-        JS_GetObjectAsArrayBuffer(obj, &length, &data);
+        JS::GetObjectAsArrayBuffer(obj, &length, &data);
       }
 
       if (NS_WARN_IF(!aData.Assign(reinterpret_cast<char*>(data), length,
                                    fallible_t()))) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       return NS_OK;
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -71,19 +71,22 @@
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsIConsoleService.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsStringBuffer.h"
 #include "nsIFileChannel.h"
 #include "mozilla/Telemetry.h"
-#include "js/JSON.h"
+#include "js/ArrayBuffer.h"  // JS::{Create,Release}MappedArrayBufferContents,New{,Mapped}ArrayBufferWithContents
+#include "js/JSON.h"         // JS_ParseJSON
 #include "js/MemoryFunctions.h"
-#include "jsfriendapi.h"
+#include "js/RootingAPI.h"  // JS::{{,Mutable}Handle,Rooted}
+#include "js/Value.h"       // JS::{,Undefined}Value
+#include "jsapi.h"          // JS_ClearPendingException
 #include "GeckoProfiler.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "mozilla/Attributes.h"
 #include "MultipartBlobImpl.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIClassOfService.h"
@@ -3624,17 +3627,17 @@ ArrayBufferBuilder::ArrayBufferBuilder()
 ArrayBufferBuilder::~ArrayBufferBuilder() { reset(); }
 
 void ArrayBufferBuilder::reset() {
   if (mDataPtr) {
     JS_free(nullptr, mDataPtr);
   }
 
   if (mMapPtr) {
-    JS_ReleaseMappedArrayBufferContents(mMapPtr, mLength);
+    JS::ReleaseMappedArrayBufferContents(mMapPtr, mLength);
     mMapPtr = nullptr;
   }
 
   mDataPtr = nullptr;
   mCapacity = mLength = 0;
 }
 
 bool ArrayBufferBuilder::setCapacity(uint32_t aNewCap) {
@@ -3700,36 +3703,36 @@ bool ArrayBufferBuilder::append(const ui
   memcpy(mDataPtr + mLength, aNewData, aDataLen);
   mLength += aDataLen;
 
   return true;
 }
 
 JSObject* ArrayBufferBuilder::getArrayBuffer(JSContext* aCx) {
   if (mMapPtr) {
-    JSObject* obj = JS_NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
+    JSObject* obj = JS::NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
     if (!obj) {
-      JS_ReleaseMappedArrayBufferContents(mMapPtr, mLength);
+      JS::ReleaseMappedArrayBufferContents(mMapPtr, mLength);
     }
     mMapPtr = nullptr;
 
     // The memory-mapped contents will be released when the ArrayBuffer becomes
     // detached or is GC'd.
     return obj;
   }
 
   // we need to check for mLength == 0, because nothing may have been
   // added
   if (mCapacity > mLength || mLength == 0) {
     if (!setCapacity(mLength)) {
       return nullptr;
     }
   }
 
-  JSObject* obj = JS_NewArrayBufferWithContents(aCx, mLength, mDataPtr);
+  JSObject* obj = JS::NewArrayBufferWithContents(aCx, mLength, mDataPtr);
   mLength = mCapacity = 0;
   if (!obj) {
     js_free(mDataPtr);
   }
   mDataPtr = nullptr;
   return obj;
 }
 
@@ -3753,17 +3756,17 @@ nsresult ArrayBufferBuilder::mapToFileIn
   if (!zipItem->Compression()) {
     uint32_t offset = zip->GetDataOffset(zipItem);
     uint32_t size = zipItem->RealSize();
     mozilla::AutoFDClose pr_fd;
     rv = aJarFile->OpenNSPRFileDesc(PR_RDONLY, 0, &pr_fd.rwget());
     if (NS_FAILED(rv)) {
       return rv;
     }
-    mMapPtr = JS_CreateMappedArrayBufferContents(
+    mMapPtr = JS::CreateMappedArrayBufferContents(
         PR_FileDesc2NativeHandle(pr_fd), offset, size);
     if (mMapPtr) {
       mLength = size;
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
 }
--- a/dom/xhr/XMLHttpRequestWorker.cpp
+++ b/dom/xhr/XMLHttpRequestWorker.cpp
@@ -5,19 +5,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XMLHttpRequestWorker.h"
 
 #include "nsIDOMEventListener.h"
 #include "nsIRunnable.h"
 #include "nsIXPConnect.h"
 
+#include "jsapi.h"  // JS::AutoValueArray
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::Is{,Detached}ArrayBufferObject
+#include "js/GCPolicyAPI.h"
+#include "js/RootingAPI.h"  // JS::{Handle,Heap},PersistentRooted
 #include "js/TracingAPI.h"
-#include "js/GCPolicyAPI.h"
+#include "js/Value.h"  // JS::{Undefined,}Value
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/ProgressEvent.h"
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/UnionConversions.h"
@@ -1029,24 +1033,24 @@ bool EventRunnable::PreDispatch(WorkerPr
     if (NS_SUCCEEDED(mResponseResult)) {
       if (!response.isGCThing()) {
         mResponse = response;
       } else {
         bool doClone = true;
         JS::Rooted<JS::Value> transferable(cx);
         JS::Rooted<JSObject*> obj(
             cx, response.isObject() ? &response.toObject() : nullptr);
-        if (obj && JS_IsArrayBufferObject(obj)) {
+        if (obj && JS::IsArrayBufferObject(obj)) {
           // Use cached response if the arraybuffer has been transfered.
           if (mProxy->mArrayBufferResponseWasTransferred) {
-            MOZ_ASSERT(JS_IsDetachedArrayBufferObject(obj));
+            MOZ_ASSERT(JS::IsDetachedArrayBufferObject(obj));
             mUseCachedArrayBufferResponse = true;
             doClone = false;
           } else {
-            MOZ_ASSERT(!JS_IsDetachedArrayBufferObject(obj));
+            MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(obj));
             JS::AutoValueArray<1> argv(cx);
             argv[0].set(response);
             obj = JS_NewArrayObject(cx, argv);
             if (obj) {
               transferable.setObject(*obj);
               // Only cache the response when the readyState is DONE.
               if (xhr->ReadyState() == 4) {
                 mProxy->mArrayBufferResponseWasTransferred = true;
@@ -1216,18 +1220,17 @@ bool EventRunnable::WorkerRun(JSContext*
   if (!event) {
     return false;
   }
 
   event->SetTrusted(true);
 
   target->DispatchEvent(*event);
 
-  // After firing the event set mResponse to JSVAL_NULL for chunked response
-  // types.
+  // After firing the event set mResponse to null for chunked response types.
   if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) {
     xhr->NullResponseText();
   }
 
   return true;
 }
 
 bool WorkerThreadProxySyncRunnable::MainThreadRun() {
@@ -2203,17 +2206,17 @@ void XMLHttpRequestWorker::GetResponseTe
     return;
   }
 }
 
 void XMLHttpRequestWorker::UpdateState(const StateData& aStateData,
                                        bool aUseCachedArrayBufferResponse) {
   if (aUseCachedArrayBufferResponse) {
     MOZ_ASSERT(mStateData.mResponse.isObject() &&
-               JS_IsArrayBufferObject(&mStateData.mResponse.toObject()));
+               JS::IsArrayBufferObject(&mStateData.mResponse.toObject()));
 
     JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
                                    mStateData.mResponse);
     mStateData = aStateData;
     mStateData.mResponse = response;
   } else {
     mStateData = aStateData;
   }
--- a/gfx/2d/DrawTargetOffset.cpp
+++ b/gfx/2d/DrawTargetOffset.cpp
@@ -160,16 +160,22 @@ void DrawTargetOffset::PushLayer(bool aO
                                  const IntRect& aBounds, bool aCopyBackground) {
   IntRect bounds = aBounds - mOrigin;
 
   mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds,
                          aCopyBackground);
   SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
 }
 
+already_AddRefed<SourceSurface> DrawTargetOffset::IntoLuminanceSource(
+    LuminanceType aLuminanceType, float aOpacity) {
+  return MakeAndAddRef<SourceSurfaceOffset>(
+      DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity), mOrigin);
+}
+
 void DrawTargetOffset::PushLayerWithBlend(bool aOpaque, Float aOpacity,
                                           SourceSurface* aMask,
                                           const Matrix& aMaskTransform,
                                           const IntRect& aBounds,
                                           bool aCopyBackground,
                                           CompositionOp aOp) {
   IntRect bounds = aBounds - mOrigin;
 
--- a/gfx/2d/DrawTargetOffset.h
+++ b/gfx/2d/DrawTargetOffset.h
@@ -21,17 +21,17 @@ namespace gfx {
 
 class SourceSurfaceOffset : public SourceSurface {
  public:
   SourceSurfaceOffset(RefPtr<SourceSurface> aSurface, IntPoint aOffset)
       : mSurface(aSurface), mOffset(aOffset) {}
   virtual SurfaceType GetType() const override { return SurfaceType::OFFSET; }
   virtual IntSize GetSize() const override { return mSurface->GetSize(); }
   virtual IntRect GetRect() const override {
-    return IntRect(mOffset, mSurface->GetSize());
+    return mSurface->GetRect() + mOffset;
   }
   virtual SurfaceFormat GetFormat() const override {
     return mSurface->GetFormat();
   }
   virtual already_AddRefed<DataSourceSurface> GetDataSurface() override {
     return mSurface->GetDataSurface();
   }
 
@@ -54,16 +54,18 @@ class DrawTargetOffset : public DrawTarg
   }
   virtual DrawTargetType GetType() const override {
     return mDrawTarget->GetType();
   }
   virtual BackendType GetBackendType() const override {
     return mDrawTarget->GetBackendType();
   }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
+  virtual already_AddRefed<SourceSurface> IntoLuminanceSource(
+      LuminanceType aLuminanceType, float aOpacity) override;
   virtual void DetachAllSnapshots() override;
   virtual IntSize GetSize() const override { return mDrawTarget->GetSize(); }
   virtual IntRect GetRect() const override {
     return IntRect(mOrigin, GetSize());
   }
 
   virtual void Flush() override;
   virtual void DrawSurface(SourceSurface *aSurface, const Rect &aDest,
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -1446,17 +1446,17 @@ void DrawTargetSkia::MaskSurface(const P
   AutoPaintSetup paint(mCanvas, aOptions, aSource, nullptr, &invOffset);
 
   sk_sp<SkImage> alphaMask = ExtractAlphaForSurface(aMask);
   if (!alphaMask) {
     gfxDebug() << *this << ": MaskSurface() failed to extract alpha for mask";
     return;
   }
 
-  mCanvas->drawImage(alphaMask, aOffset.x, aOffset.y, &paint.mPaint);
+  mCanvas->drawImage(alphaMask, aOffset.x + aMask->GetRect().x, aOffset.y + aMask->GetRect().y, &paint.mPaint);
 }
 
 bool DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface,
                                           const Matrix4x4& aMatrix) {
   // Composite the 3D transform with the DT's transform.
   Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
   if (fullMat.IsSingular()) {
     return false;
@@ -1835,17 +1835,17 @@ void DrawTargetSkia::PushLayerWithBlend(
       bounds.setEmpty();
     }
   }
 
   sk_sp<SkImage> clipImage = aMask ? GetSkImageForSurface(aMask) : nullptr;
   SkMatrix clipMatrix;
   GfxMatrixToSkiaMatrix(aMaskTransform, clipMatrix);
   if (aMask) {
-    clipMatrix.postTranslate(aMask->GetRect().X(), aMask->GetRect().Y());
+    clipMatrix.preTranslate(aMask->GetRect().X(), aMask->GetRect().Y());
   }
 
   SkCanvas::SaveLayerRec saveRec(
       aBounds.IsEmpty() ? nullptr : &bounds, &paint, nullptr, clipImage.get(),
       &clipMatrix,
       SkCanvas::kPreserveLCDText_SaveLayerFlag |
           (aCopyBackground ? SkCanvas::kInitWithPrevious_SaveLayerFlag : 0));
 
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -1996,31 +1996,30 @@ inline bool RecordedCreateDrawTargetForF
   return true;
 }
 
 inline bool RecordedCreateClippedDrawTarget::PlayEvent(
     Translator *aTranslator) const {
   const IntRect baseRect = aTranslator->GetReferenceDrawTarget()->GetRect();
   const IntRect transformedRect = RoundedToInt(
       mTransform.Inverse().TransformBounds(IntRectToRect(baseRect)));
-  const IntRect intersection =
+  IntRect intersection =
       IntRect(IntPoint(0, 0), mMaxSize).Intersect(transformedRect);
 
+  // Making 0 size DrawTargets isn't great. So let's make sure we have a size of
+  // at least 1
+  if (intersection.width == 0) intersection.width = 1;
+  if (intersection.height == 0) intersection.height = 1;
+
   RefPtr<DrawTarget> newDT =
       aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(
-          intersection.Size(), SurfaceFormat::A8);
+          intersection.Size(), mFormat);
   // It's overkill to use a TiledDrawTarget for a single tile
   // but it was the easiest way to get the offset handling working
-  gfx::TileSet tileset;
-  gfx::Tile tile;
-  tile.mDrawTarget = newDT;
-  tile.mTileOrigin = gfx::IntPoint(intersection.X(), intersection.Y());
-  tileset.mTiles = &tile;
-  tileset.mTileCount = 1;
-  newDT = gfx::Factory::CreateTiledDrawTarget(tileset);
+  newDT = gfx::Factory::CreateOffsetDrawTarget(newDT, intersection.TopLeft());
 
   // If we couldn't create a DrawTarget this will probably cause us to crash
   // with nullptr later in the playback, so return false to abort.
   if (!newDT) {
     return false;
   }
 
   aTranslator->AddDrawTarget(mRefPtr, newDT);
--- a/image/imgTools.cpp
+++ b/image/imgTools.cpp
@@ -23,17 +23,19 @@
 #include "nsStringStream.h"
 #include "nsContentUtils.h"
 #include "nsProxyRelease.h"
 #include "ImageFactory.h"
 #include "Image.h"
 #include "ScriptedNotificationObserver.h"
 #include "imgIScriptedNotificationObserver.h"
 #include "gfxPlatform.h"
-#include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"
+#include "js/RootingAPI.h"  // JS::{Handle,Rooted}
+#include "js/Value.h"       // JS::Value
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
 namespace {
 
@@ -164,35 +166,35 @@ NS_IMPL_ISUPPORTS(imgTools, imgITools)
 
 imgTools::imgTools() { /* member initializers and constructor code */
 }
 
 imgTools::~imgTools() { /* destructor code */
 }
 
 NS_IMETHODIMP
-imgTools::DecodeImageFromArrayBuffer(JS::HandleValue aArrayBuffer,
+imgTools::DecodeImageFromArrayBuffer(JS::Handle<JS::Value> aArrayBuffer,
                                      const nsACString& aMimeType,
                                      JSContext* aCx,
                                      imgIContainer** aContainer) {
   if (!aArrayBuffer.isObject()) {
     return NS_ERROR_FAILURE;
   }
 
   JS::Rooted<JSObject*> obj(aCx,
-                            js::UnwrapArrayBuffer(&aArrayBuffer.toObject()));
+                            JS::UnwrapArrayBuffer(&aArrayBuffer.toObject()));
   if (!obj) {
     return NS_ERROR_FAILURE;
   }
 
   uint8_t* bufferData = nullptr;
   uint32_t bufferLength = 0;
   bool isSharedMemory = false;
 
-  js::GetArrayBufferLengthAndData(obj, &bufferLength, &isSharedMemory,
+  JS::GetArrayBufferLengthAndData(obj, &bufferLength, &isSharedMemory,
                                   &bufferData);
   return DecodeImageFromBuffer((char*)bufferData, bufferLength, aMimeType,
                                aContainer);
 }
 
 NS_IMETHODIMP
 imgTools::DecodeImageFromBuffer(const char* aBuffer, uint32_t aSize,
                                 const nsACString& aMimeType,
new file mode 100644
--- /dev/null
+++ b/js/public/ArrayBuffer.h
@@ -0,0 +1,237 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* ArrayBuffer functionality. */
+
+#ifndef js_ArrayBuffer_h
+#define js_ArrayBuffer_h
+
+#include <stddef.h>  // size_t
+#include <stdint.h>  // uint32_t
+
+#include "jstypes.h"  // JS_PUBLIC_API
+
+#include "js/GCAPI.h"       // JS::AutoRequireNoGC
+#include "js/RootingAPI.h"  // JS::Handle
+
+struct JSContext;
+class JSObject;
+
+namespace JS {
+
+// CREATION
+
+/**
+ * Create a new ArrayBuffer with the given byte length.
+ */
+extern JS_PUBLIC_API JSObject* NewArrayBuffer(JSContext* cx, uint32_t nbytes);
+
+/**
+ * Create a new ArrayBuffer with the given |contents|, which may be null only
+ * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
+ * by |JS_free|.
+ *
+ * If and only if an ArrayBuffer is successfully created and returned,
+ * ownership of |contents| is transferred to the new ArrayBuffer.
+ */
+extern JS_PUBLIC_API JSObject* NewArrayBufferWithContents(JSContext* cx,
+                                                          size_t nbytes,
+                                                          void* contents);
+
+using BufferContentsFreeFunc = void (*)(void* contents, void* userData);
+
+/**
+ * Create a new ArrayBuffer with the given contents. The contents must not be
+ * modified by any other code, internal or external.
+ *
+ * When the ArrayBuffer is ready to be disposed of, `freeFunc(contents,
+ * freeUserData)` will be called to release the ArrayBuffer's reference on the
+ * contents.
+ *
+ * `freeFunc()` must not call any JSAPI functions that could cause a garbage
+ * collection.
+ *
+ * The caller must keep the buffer alive until `freeFunc()` is called, or, if
+ * `freeFunc` is null, until the JSRuntime is destroyed.
+ *
+ * The caller must not access the buffer on other threads. The JS engine will
+ * not allow the buffer to be transferred to other threads. If you try to
+ * transfer an external ArrayBuffer to another thread, the data is copied to a
+ * new malloc buffer. `freeFunc()` must be threadsafe, and may be called from
+ * any thread.
+ *
+ * This allows ArrayBuffers to be used with embedder objects that use reference
+ * counting, for example. In that case the caller is responsible
+ * for incrementing the reference count before passing the contents to this
+ * function. This also allows using non-reference-counted contents that must be
+ * freed with some function other than free().
+ */
+extern JS_PUBLIC_API JSObject* NewExternalArrayBuffer(
+    JSContext* cx, size_t nbytes, void* contents,
+    BufferContentsFreeFunc freeFunc, void* freeUserData = nullptr);
+
+/**
+ * Create a new ArrayBuffer with the given non-null |contents|.
+ *
+ * Ownership of |contents| remains with the caller: it isn't transferred to the
+ * returned ArrayBuffer.  Callers of this function *must* ensure that they
+ * perform these two steps, in this order, to properly relinquish ownership of
+ * |contents|:
+ *
+ *   1. Call |JS::DetachArrayBuffer| on the buffer returned by this function.
+ *      (|JS::DetachArrayBuffer| is generally fallible, but a call under these
+ *      circumstances is guaranteed to succeed.)
+ *   2. |contents| may be deallocated or discarded consistent with the manner
+ *      in which it was allocated.
+ *
+ * Do not simply allow the returned buffer to be garbage-collected before
+ * deallocating |contents|, because in general there is no way to know *when*
+ * an object is fully garbage-collected to the point where this would be safe.
+ */
+extern JS_PUBLIC_API JSObject* NewArrayBufferWithUserOwnedContents(
+    JSContext* cx, size_t nbytes, void* contents);
+
+/**
+ * Create a new mapped ArrayBuffer with the given memory mapped contents. It
+ * must be legal to free the contents pointer by unmapping it. On success,
+ * ownership is transferred to the new mapped ArrayBuffer.
+ */
+extern JS_PUBLIC_API JSObject* NewMappedArrayBufferWithContents(JSContext* cx,
+                                                                size_t nbytes,
+                                                                void* contents);
+
+/**
+ * Create memory mapped ArrayBuffer contents.
+ * Caller must take care of closing fd after calling this function.
+ */
+extern JS_PUBLIC_API void* CreateMappedArrayBufferContents(int fd,
+                                                           size_t offset,
+                                                           size_t length);
+
+/**
+ * Release the allocated resource of mapped ArrayBuffer contents before the
+ * object is created.
+ * If a new object has been created by JS::NewMappedArrayBufferWithContents()
+ * with this content, then JS::DetachArrayBuffer() should be used instead to
+ * release the resource used by the object.
+ */
+extern JS_PUBLIC_API void ReleaseMappedArrayBufferContents(void* contents,
+                                                           size_t length);
+
+// TYPE TESTING
+
+/*
+ * Check whether obj supports the JS::GetArrayBuffer* APIs.  Note that this may
+ * return false if a security wrapper is encountered that denies the unwrapping.
+ * If this test succeeds, then it is safe to call the various predicate and
+ * accessor JSAPI calls defined below.
+ */
+extern JS_PUBLIC_API bool IsArrayBufferObject(JSObject* obj);
+
+// PREDICATES
+
+/**
+ * Check whether the obj is a detached ArrayBufferObject. Note that this may
+ * return false if a security wrapper is encountered that denies the
+ * unwrapping.
+ */
+extern JS_PUBLIC_API bool IsDetachedArrayBufferObject(JSObject* obj);
+
+/**
+ * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
+ * may return false if a security wrapper is encountered that denies the
+ * unwrapping.
+ */
+extern JS_PUBLIC_API bool IsMappedArrayBufferObject(JSObject* obj);
+
+/**
+ * Return true if the ArrayBuffer |obj| contains any data, i.e. it is not a
+ * detached ArrayBuffer.  (ArrayBuffer.prototype is not an ArrayBuffer.)
+ *
+ * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
+ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
+ * ArrayBuffer, and the unwrapping will succeed.
+ */
+extern JS_PUBLIC_API bool ArrayBufferHasData(JSObject* obj);
+
+// ACCESSORS
+
+extern JS_PUBLIC_API JSObject* UnwrapArrayBuffer(JSObject* obj);
+
+/**
+ * Attempt to unwrap |obj| as an ArrayBuffer.
+ *
+ * If |obj| *is* an ArrayBuffer, return it unwrapped and set |*length| and
+ * |*data| to weakly refer to the ArrayBuffer's contents.
+ *
+ * If |obj| isn't an ArrayBuffer, return nullptr and do not modify |*length| or
+ * |*data|.
+ */
+extern JS_PUBLIC_API JSObject* GetObjectAsArrayBuffer(JSObject* obj,
+                                                      uint32_t* length,
+                                                      uint8_t** data);
+
+/**
+ * Return the available byte length of an ArrayBuffer.
+ *
+ * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
+ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
+ * ArrayBuffer, and the unwrapping will succeed.
+ */
+extern JS_PUBLIC_API uint32_t GetArrayBufferByteLength(JSObject* obj);
+
+// This one isn't inlined because there are a bunch of different ArrayBuffer
+// classes that would have to be individually handled here.
+//
+// There is an isShared out argument for API consistency (eases use from DOM).
+// It will always be set to false.
+extern JS_PUBLIC_API void GetArrayBufferLengthAndData(JSObject* obj,
+                                                      uint32_t* length,
+                                                      bool* isSharedMemory,
+                                                      uint8_t** data);
+
+/**
+ * Return a pointer to the start of the data referenced by a typed array. The
+ * data is still owned by the typed array, and should not be modified on
+ * another thread. Furthermore, the pointer can become invalid on GC (if the
+ * data is small and fits inside the array's GC header), so callers must take
+ * care not to hold on across anything that could GC.
+ *
+ * |obj| must have passed a JS::IsArrayBufferObject test, or somehow be known
+ * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
+ * ArrayBuffer, and the unwrapping will succeed.
+ *
+ * |*isSharedMemory| is always set to false.  The argument is present to
+ * simplify its use from code that also interacts with SharedArrayBuffer.
+ */
+extern JS_PUBLIC_API uint8_t* GetArrayBufferData(JSObject* obj,
+                                                 bool* isSharedMemory,
+                                                 const AutoRequireNoGC&);
+
+// MUTATORS
+
+/**
+ * Detach an ArrayBuffer, causing all associated views to no longer refer to
+ * the ArrayBuffer's original attached memory.
+ *
+ * This function throws only if it is provided a non-ArrayBuffer object or if
+ * the provided ArrayBuffer is a WASM-backed ArrayBuffer or an ArrayBuffer used
+ * in asm.js code.
+ */
+extern JS_PUBLIC_API bool DetachArrayBuffer(JSContext* cx,
+                                            Handle<JSObject*> obj);
+
+/**
+ * Steal the contents of the given ArrayBuffer. The ArrayBuffer has its length
+ * set to 0 and its contents array cleared. The caller takes ownership of the
+ * return value and must free it or transfer ownership via
+ * JS::NewArrayBufferWithContents when done using it.
+ */
+extern JS_PUBLIC_API void* StealArrayBufferContents(JSContext* cx,
+                                                    Handle<JSObject*> obj);
+
+}  // namespace JS
+
+#endif /* js_ArrayBuffer_h */
new file mode 100644
--- /dev/null
+++ b/js/public/SharedArrayBuffer.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* ArrayBuffer functionality. */
+
+#ifndef js_SharedArrayBuffer_h
+#define js_SharedArrayBuffer_h
+
+#include <stddef.h>  // size_t
+#include <stdint.h>  // uint32_t
+
+#include "jstypes.h"  // JS_PUBLIC_API
+
+#include "js/GCAPI.h"  // JS::AutoRequireNoGC
+
+struct JSContext;
+class JSObject;
+
+namespace JS {
+
+// CREATION
+
+/**
+ * Create a new SharedArrayBuffer with the given byte length.  This
+ * may only be called if
+ * JS::RealmCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is
+ * true.
+ */
+extern JS_PUBLIC_API JSObject* NewSharedArrayBuffer(JSContext* cx,
+                                                    uint32_t nbytes);
+
+// TYPE TESTING
+
+/**
+ * Check whether obj supports the JS::GetSharedArrayBuffer* APIs.  Note that
+ * this may return false if a security wrapper is encountered that denies the
+ * unwrapping. If this test succeeds, then it is safe to call the various
+ * accessor JSAPI calls defined below.
+ */
+extern JS_PUBLIC_API bool IsSharedArrayBufferObject(JSObject* obj);
+
+// ACCESSORS
+
+extern JS_PUBLIC_API JSObject* UnwrapSharedArrayBuffer(JSObject* obj);
+
+extern JS_PUBLIC_API uint32_t GetSharedArrayBufferByteLength(JSObject* obj);
+
+extern JS_PUBLIC_API uint8_t* GetSharedArrayBufferData(JSObject* obj,
+                                                       bool* isSharedMemory,
+                                                       const AutoRequireNoGC&);
+
+// Ditto for SharedArrayBuffer.
+//
+// There is an isShared out argument for API consistency (eases use from DOM).
+// It will always be set to true.
+extern JS_PUBLIC_API void GetSharedArrayBufferLengthAndData(
+    JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
+
+}  // namespace JS
+
+#endif /* js_SharedArrayBuffer_h */
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -279,17 +279,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_CopyPropertiesFrom",
     "JS::CurrentGlobalOrNull",
     "JS_DeletePropertyById",
     "js::detail::IsWindowSlow",
     "JS::Evaluate",
     "JS_ForwardGetPropertyTo",
     "JS_ForwardSetPropertyTo",
     "JS::GCTraceKindToAscii",
-    "js::GetArrayBufferLengthAndData",
+    "JS::GetArrayBufferLengthAndData",
     "js::GetArrayBufferViewLengthAndData",
     "js::GetFunctionNativeReserved",
     "JS::GetNonCCWObjectGlobal",
     "js::GetObjectProto",
     "JS_GetObjectRuntime",
     "JS_GetOwnPropertyDescriptorById",
     "JS::GetPromiseResult",
     "JS::GetPromiseState",
@@ -320,17 +320,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS::DisableIncrementalGC",
     "js::Dump.*",
     "JS::EnterRealm",
     "JS_EnumerateStandardClasses",
     "JS_ErrorFromException",
     "JS_FireOnNewGlobalObject",
     "JS_free",
     "JS_GC",
-    "JS_GetArrayBufferData",
+    "JS::GetArrayBufferData",
     "JS_GetArrayBufferViewType",
     "JS_GetFloat32ArrayData",
     "JS_GetFloat64ArrayData",
     "JS_GetFunctionObject",
     "JS_GetGCParameter",
     "JS_GetInt16ArrayData",
     "JS_GetInt32ArrayData",
     "JS_GetInt8ArrayData",
@@ -358,17 +358,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS::InitRealmStandardClasses",
     "JS_IsArrayObject",
     "JS_IsExceptionPending",
     "JS_IsGlobalObject",
     "JS::IsCallable",
     "JS::LeaveRealm",
     "JS_LinkConstructorAndPrototype",
     "JS_MayResolveStandardClass",
-    "JS_NewArrayBuffer",
+    "JS::NewArrayBuffer",
     "JS_NewArrayObject",
     "JS_NewContext",
     "JS_NewFloat32Array",
     "JS_NewFloat64Array",
     "JS_NewFunction",
     "js::NewFunctionWithReserved",
     "JS_NewGlobalObject",
     "JS_NewInt16Array",
@@ -443,17 +443,17 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "js::ToNumberSlow",
     "js::ToStringSlow",
     "js::ToUint16Slow",
     "js::ToUint32Slow",
     "js::ToUint64Slow",
     "JS_TransplantObject",
     "js::detail::ToWindowProxyIfWindowSlow",
     "JS::UnhideScriptedCaller",
-    "js::UnwrapArrayBuffer",
+    "JS::UnwrapArrayBuffer",
     "js::UnwrapArrayBufferView",
     "js::UnwrapFloat32Array",
     "js::UnwrapFloat64Array",
     "js::UnwrapInt16Array",
     "js::UnwrapInt32Array",
     "js::UnwrapInt8Array",
     "js::UnwrapUint16Array",
     "js::UnwrapUint32Array",
--- a/js/rust/etc/wrapper.hpp
+++ b/js/rust/etc/wrapper.hpp
@@ -8,16 +8,17 @@
 #ifndef _MSC_VER
 #include <unistd.h>
 #endif
 
 typedef uint32_t HashNumber;
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/ContextOptions.h"
 #include "js/Conversions.h"
 #include "js/Date.h"
 #include "js/Initialization.h"
 #include "js/MemoryMetrics.h"
 #include "js/PropertySpec.h"
--- a/js/rust/src/typedarray.rs
+++ b/js/rust/src/typedarray.rs
@@ -247,18 +247,18 @@ typed_array_element!(ClampedU8,
                      UnwrapUint8ClampedArray,
                      GetUint8ClampedArrayLengthAndData,
                      JS_NewUint8ClampedArray,
                      JS_GetUint8ClampedArrayData);
 typed_array_element!(ArrayBufferU8,
                      u8,
                      UnwrapArrayBuffer,
                      GetArrayBufferLengthAndData,
-                     JS_NewArrayBuffer,
-                     JS_GetArrayBufferData);
+                     NewArrayBuffer,
+                     GetArrayBufferData);
 typed_array_element!(ArrayBufferViewU8,
                      u8,
                      UnwrapArrayBufferView,
                      GetArrayBufferViewLengthAndData);
 
 /// The Uint8ClampedArray type.
 pub type Uint8ClampedArray<'a> = TypedArray<'a, ClampedU8>;
 /// The Uint8Array type.
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -4,16 +4,17 @@
  * 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 "builtin/Stream.h"
 
 #include "js/Stream.h"
 
 #include "gc/Heap.h"
+#include "js/ArrayBuffer.h"  // JS::NewArrayBuffer
 #include "js/PropertySpec.h"
 #include "vm/Interpreter.h"
 #include "vm/JSContext.h"
 #include "vm/SelfHosting.h"
 
 #include "vm/Compartment-inl.h"
 #include "vm/List-inl.h"
 #include "vm/NativeObject-inl.h"
@@ -3727,17 +3728,17 @@ static MOZ_MUST_USE JSObject* ReadableBy
   val = unwrappedController->autoAllocateChunkSize();
 
   // Step 5: If autoAllocateChunkSize is not undefined,
   if (!val.isUndefined()) {
     double autoAllocateChunkSize = val.toNumber();
 
     // Step 5.a: Let buffer be
     //           Construct(%ArrayBuffer%, « autoAllocateChunkSize »).
-    JSObject* bufferObj = JS_NewArrayBuffer(cx, autoAllocateChunkSize);
+    JSObject* bufferObj = JS::NewArrayBuffer(cx, autoAllocateChunkSize);
 
     // Step 5.b: If buffer is an abrupt completion,
     //           return a promise rejected with buffer.[[Value]].
     if (!bufferObj) {
       return PromiseRejectedWithPendingError(cx);
     }
 
     RootedArrayBufferObject buffer(cx, &bufferObj->as<ArrayBufferObject>());
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -36,16 +36,17 @@
 #  include "irregexp/RegExpAST.h"
 #  include "irregexp/RegExpEngine.h"
 #  include "irregexp/RegExpParser.h"
 #endif
 #include "gc/Heap.h"
 #include "jit/BaselineJIT.h"
 #include "jit/InlinableNatives.h"
 #include "jit/JitRealm.h"
+#include "js/ArrayBuffer.h"  // JS::{DetachArrayBuffer,GetArrayBufferLengthAndData,NewArrayBufferWithContents}
 #include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/Debug.h"
 #include "js/HashTable.h"
 #include "js/LocaleSensitive.h"
 #include "js/PropertySpec.h"
 #include "js/SourceText.h"
@@ -2841,17 +2842,17 @@ class CloneBufferObject : public NativeO
     const char* data = nullptr;
     UniqueChars dataOwner;
     uint32_t nbytes;
 
     if (args.get(0).isObject() && args[0].toObject().is<ArrayBufferObject>()) {
       ArrayBufferObject* buffer = &args[0].toObject().as<ArrayBufferObject>();
       bool isSharedMemory;
       uint8_t* dataBytes = nullptr;
-      js::GetArrayBufferLengthAndData(buffer, &nbytes, &isSharedMemory,
+      JS::GetArrayBufferLengthAndData(buffer, &nbytes, &isSharedMemory,
                                       &dataBytes);
       MOZ_ASSERT(!isSharedMemory);
       data = reinterpret_cast<char*>(dataBytes);
     } else {
       JSString* str = JS::ToString(cx, args.get(0));
       if (!str) {
         return false;
       }
@@ -2961,17 +2962,17 @@ class CloneBufferObject : public NativeO
     if (!buffer) {
       ReportOutOfMemory(cx);
       return false;
     }
     auto iter = data->Start();
     data->ReadBytes(iter, buffer.get(), size);
 
     auto* rawBuffer = buffer.release();
-    JSObject* arrayBuffer = JS_NewArrayBufferWithContents(cx, size, rawBuffer);
+    JSObject* arrayBuffer = JS::NewArrayBufferWithContents(cx, size, rawBuffer);
     if (!arrayBuffer) {
       js_free(rawBuffer);
       return false;
     }
 
     args.rval().setObject(*arrayBuffer);
     return true;
   }
@@ -3185,17 +3186,17 @@ static bool DetachArrayBuffer(JSContext*
   }
 
   if (!args[0].isObject()) {
     JS_ReportErrorASCII(cx, "detachArrayBuffer must be passed an object");
     return false;
   }
 
   RootedObject obj(cx, &args[0].toObject());
-  if (!JS_DetachArrayBuffer(cx, obj)) {
+  if (!JS::DetachArrayBuffer(cx, obj)) {
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 
 static bool HelperThreadCount(JSContext* cx, unsigned argc, Value* vp) {
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -34,18 +34,20 @@
 #include "jsexn.h"
 #include "jsnum.h"
 
 #include "builtin/TypedObject.h"
 #include "ctypes/Library.h"
 #include "gc/FreeOp.h"
 #include "gc/Policy.h"
 #include "jit/AtomicOperations.h"
+#include "js/ArrayBuffer.h"  // JS::{IsArrayBufferObject,GetArrayBufferData,GetArrayBuffer{ByteLength,Data}}
 #include "js/CharacterEncoding.h"
 #include "js/PropertySpec.h"
+#include "js/SharedArrayBuffer.h"  // JS::{GetSharedArrayBuffer{ByteLength,Data},IsSharedArrayBufferObject}
 #include "js/StableStringChars.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 #include "util/Unicode.h"
 #include "util/Windows.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
@@ -3378,39 +3380,39 @@ static bool ImplicitConvert(JSContext* c
             (*char16Buffer)[sourceLength] = 0;
             break;
           }
           default:
             return ConvError(cx, targetType, val, convType, funObj, argIndex,
                              arrObj, arrIndex);
         }
         break;
-      } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
+      } else if (val.isObject() && JS::IsArrayBufferObject(valObj)) {
         // Convert ArrayBuffer to pointer without any copy. This is only valid
         // when converting an argument to a function call, as it is possible for
         // the pointer to be invalidated by anything that runs JS code. (It is
         // invalid to invoke JS code from a ctypes function call.)
         if (convType != ConversionType::Argument) {
           return ConvError(cx, targetType, val, convType, funObj, argIndex,
                            arrObj, arrIndex);
         }
         void* ptr;
         {
           JS::AutoCheckCannotGC nogc;
           bool isShared;
-          ptr = JS_GetArrayBufferData(valObj, &isShared, nogc);
+          ptr = JS::GetArrayBufferData(valObj, &isShared, nogc);
           MOZ_ASSERT(!isShared);  // Because ArrayBuffer
         }
         if (!ptr) {
           return ConvError(cx, targetType, val, convType, funObj, argIndex,
                            arrObj, arrIndex);
         }
         *static_cast<void**>(buffer) = ptr;
         break;
-      } else if (val.isObject() && JS_IsSharedArrayBufferObject(valObj)) {
+      } else if (val.isObject() && JS::IsSharedArrayBufferObject(valObj)) {
         // CTypes has not yet opted in to allowing shared memory pointers
         // to escape.  Exporting a pointer to the shared buffer without
         // indicating sharedness would expose client code to races.
         return ConvError(cx, targetType, val, convType, funObj, argIndex,
                          arrObj, arrIndex);
       } else if (val.isObject() && JS_IsArrayBufferViewObject(valObj)) {
         // Same as ArrayBuffer, above, though note that this will take the
         // offset of the view into account.
@@ -3555,34 +3557,34 @@ static bool ImplicitConvert(JSContext* c
 
           memcpy(buffer, intermediate.get(), arraySize);
         } else if (cls == ESClass::ArrayBuffer ||
                    cls == ESClass::SharedArrayBuffer) {
           // Check that array is consistent with type, then
           // copy the array.
           const bool bufferShared = cls == ESClass::SharedArrayBuffer;
           uint32_t sourceLength =
-              bufferShared ? JS_GetSharedArrayBufferByteLength(valObj)
-                           : JS_GetArrayBufferByteLength(valObj);
+              bufferShared ? JS::GetSharedArrayBufferByteLength(valObj)
+                           : JS::GetArrayBufferByteLength(valObj);
           size_t elementSize = CType::GetSize(baseType);
           size_t arraySize = elementSize * targetLength;
           if (arraySize != size_t(sourceLength)) {
             MOZ_ASSERT(!funObj);
             return ArrayLengthMismatch(cx, arraySize, targetType,
                                        size_t(sourceLength), val, convType);
           }
           SharedMem<void*> target = SharedMem<void*>::unshared(buffer);
           JS::AutoCheckCannotGC nogc;
           bool isShared;
           SharedMem<void*> src =
               (bufferShared
                    ? SharedMem<void*>::shared(
-                         JS_GetSharedArrayBufferData(valObj, &isShared, nogc))
+                         JS::GetSharedArrayBufferData(valObj, &isShared, nogc))
                    : SharedMem<void*>::unshared(
-                         JS_GetArrayBufferData(valObj, &isShared, nogc)));
+                         JS::GetArrayBufferData(valObj, &isShared, nogc)));
           MOZ_ASSERT(isShared == bufferShared);
           jit::AtomicOperations::memcpySafeWhenRacy(target, src, sourceLength);
           break;
         } else if (JS_IsTypedArrayObject(valObj)) {
           // Check that array is consistent with type, then
           // copy the array.  It is OK to copy from shared to unshared
           // or vice versa.
           if (!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -1,145 +1,147 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  */
 
 #include "jsfriendapi.h"
 
 #include "builtin/TestingFunctions.h"
+#include "js/ArrayBuffer.h"  // JS::{GetArrayBuffer{ByteLength,Data},IsArrayBufferObject,NewArrayBuffer{,WithContents},StealArrayBufferContents}
 #include "js/MemoryFunctions.h"
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testArrayBuffer_bug720949_steal) {
   static const unsigned NUM_TEST_BUFFERS = 2;
   static const unsigned MAGIC_VALUE_1 = 3;
   static const unsigned MAGIC_VALUE_2 = 17;
 
   JS::RootedObject buf_len1(cx), buf_len200(cx);
   JS::RootedObject tarray_len1(cx), tarray_len200(cx);
 
   uint32_t sizes[NUM_TEST_BUFFERS] = {sizeof(uint32_t), 200 * sizeof(uint32_t)};
   JS::HandleObject testBuf[NUM_TEST_BUFFERS] = {buf_len1, buf_len200};
   JS::HandleObject testArray[NUM_TEST_BUFFERS] = {tarray_len1, tarray_len200};
 
   // Single-element ArrayBuffer (uses fixed slots for storage)
-  CHECK(buf_len1 = JS_NewArrayBuffer(cx, sizes[0]));
+  CHECK(buf_len1 = JS::NewArrayBuffer(cx, sizes[0]));
   CHECK(tarray_len1 = JS_NewInt32ArrayWithBuffer(cx, testBuf[0], 0, -1));
 
   CHECK(JS_SetElement(cx, testArray[0], 0, MAGIC_VALUE_1));
 
   // Many-element ArrayBuffer (uses dynamic storage)
-  CHECK(buf_len200 = JS_NewArrayBuffer(cx, 200 * sizeof(uint32_t)));
+  CHECK(buf_len200 = JS::NewArrayBuffer(cx, 200 * sizeof(uint32_t)));
   CHECK(tarray_len200 = JS_NewInt32ArrayWithBuffer(cx, testBuf[1], 0, -1));
 
   for (unsigned i = 0; i < NUM_TEST_BUFFERS; i++) {
     JS::HandleObject obj = testBuf[i];
     JS::HandleObject view = testArray[i];
     uint32_t size = sizes[i];
     JS::RootedValue v(cx);
 
     // Byte lengths should all agree
-    CHECK(JS_IsArrayBufferObject(obj));
-    CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), size);
+    CHECK(JS::IsArrayBufferObject(obj));
+    CHECK_EQUAL(JS::GetArrayBufferByteLength(obj), size);
     CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
     CHECK(v.isInt32(size));
     CHECK(JS_GetProperty(cx, view, "byteLength", &v));
     CHECK(v.isInt32(size));
 
     // Modifying the underlying data should update the value returned through
     // the view
     {
       JS::AutoCheckCannotGC nogc;
       bool sharedDummy;
-      uint8_t* data = JS_GetArrayBufferData(obj, &sharedDummy, nogc);
+      uint8_t* data = JS::GetArrayBufferData(obj, &sharedDummy, nogc);
       CHECK(data != nullptr);
       *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
     }
     CHECK(JS_GetElement(cx, view, 0, &v));
     CHECK(v.isInt32(MAGIC_VALUE_2));
 
     // Steal the contents
-    void* contents = JS_StealArrayBufferContents(cx, obj);
+    void* contents = JS::StealArrayBufferContents(cx, obj);
     CHECK(contents != nullptr);
 
-    CHECK(JS_IsDetachedArrayBufferObject(obj));
+    CHECK(JS::IsDetachedArrayBufferObject(obj));
 
     // Transfer to a new ArrayBuffer
-    JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
-    CHECK(JS_IsArrayBufferObject(dst));
+    JS::RootedObject dst(cx,
+                         JS::NewArrayBufferWithContents(cx, size, contents));
+    CHECK(JS::IsArrayBufferObject(dst));
     {
       JS::AutoCheckCannotGC nogc;
       bool sharedDummy;
-      (void)JS_GetArrayBufferData(obj, &sharedDummy, nogc);
+      (void)JS::GetArrayBufferData(obj, &sharedDummy, nogc);
     }
 
     JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
     CHECK(dstview != nullptr);
 
-    CHECK_EQUAL(JS_GetArrayBufferByteLength(dst), size);
+    CHECK_EQUAL(JS::GetArrayBufferByteLength(dst), size);
     {
       JS::AutoCheckCannotGC nogc;
       bool sharedDummy;
-      uint8_t* data = JS_GetArrayBufferData(dst, &sharedDummy, nogc);
+      uint8_t* data = JS::GetArrayBufferData(dst, &sharedDummy, nogc);
       CHECK(data != nullptr);
       CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
     }
     CHECK(JS_GetElement(cx, dstview, 0, &v));
     CHECK(v.isInt32(MAGIC_VALUE_2));
   }
 
   return true;
 }
 END_TEST(testArrayBuffer_bug720949_steal)
 
 // Varying number of views of a buffer, to test the detachment weak pointers
 BEGIN_TEST(testArrayBuffer_bug720949_viewList) {
   JS::RootedObject buffer(cx);
 
   // No views
-  buffer = JS_NewArrayBuffer(cx, 2000);
+  buffer = JS::NewArrayBuffer(cx, 2000);
   buffer = nullptr;
   GC(cx);
 
   // One view.
   {
-    buffer = JS_NewArrayBuffer(cx, 2000);
+    buffer = JS::NewArrayBuffer(cx, 2000);
     JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
-    void* contents = JS_StealArrayBufferContents(cx, buffer);
+    void* contents = JS::StealArrayBufferContents(cx, buffer);
     CHECK(contents != nullptr);
     JS_free(nullptr, contents);
     GC(cx);
     CHECK(hasDetachedBuffer(view));
-    CHECK(JS_IsDetachedArrayBufferObject(buffer));
+    CHECK(JS::IsDetachedArrayBufferObject(buffer));
     view = nullptr;
     GC(cx);
     buffer = nullptr;
     GC(cx);
   }
 
   // Two views
   {
-    buffer = JS_NewArrayBuffer(cx, 2000);
+    buffer = JS::NewArrayBuffer(cx, 2000);
 
     JS::RootedObject view1(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
     JS::RootedObject view2(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200));
 
     // Remove, re-add a view
     view2 = nullptr;
     GC(cx);
     view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
 
     // Detach
-    void* contents = JS_StealArrayBufferContents(cx, buffer);
+    void* contents = JS::StealArrayBufferContents(cx, buffer);
     CHECK(contents != nullptr);
     JS_free(nullptr, contents);
 
     CHECK(hasDetachedBuffer(view1));
     CHECK(hasDetachedBuffer(view2));
-    CHECK(JS_IsDetachedArrayBufferObject(buffer));
+    CHECK(JS::IsDetachedArrayBufferObject(buffer));
 
     view1 = nullptr;
     GC(cx);
     view2 = nullptr;
     GC(cx);
     buffer = nullptr;
     GC(cx);
   }
@@ -159,25 +161,25 @@ bool hasDetachedBuffer(JS::HandleObject 
 
 END_TEST(testArrayBuffer_bug720949_viewList)
 
 BEGIN_TEST(testArrayBuffer_customFreeFunc) {
   ExternalData data("One two three four");
 
   // The buffer takes ownership of the data.
   JS::RootedObject buffer(
-      cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
-                                    &ExternalData::freeCallback, &data));
+      cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
+                                     &ExternalData::freeCallback, &data));
   CHECK(buffer);
   CHECK(!data.wasFreed());
 
   uint32_t len;
   bool isShared;
   uint8_t* bufferData;
-  js::GetArrayBufferLengthAndData(buffer, &len, &isShared, &bufferData);
+  JS::GetArrayBufferLengthAndData(buffer, &len, &isShared, &bufferData);
   CHECK_EQUAL(len, data.len());
   CHECK(bufferData == data.contents());
   CHECK(strcmp(reinterpret_cast<char*>(bufferData), data.asString()) == 0);
 
   buffer = nullptr;
   JS_GC(cx);
   JS_GC(cx);
   CHECK(data.wasFreed());
@@ -186,24 +188,24 @@ BEGIN_TEST(testArrayBuffer_customFreeFun
 }
 END_TEST(testArrayBuffer_customFreeFunc)
 
 BEGIN_TEST(testArrayBuffer_staticContents) {
   ExternalData data("One two three four");
 
   // When not passing a free function, the buffer doesn't own the data.
   JS::RootedObject buffer(
-      cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(), nullptr));
+      cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(), nullptr));
   CHECK(buffer);
   CHECK(!data.wasFreed());
 
   uint32_t len;
   bool isShared;
   uint8_t* bufferData;
-  js::GetArrayBufferLengthAndData(buffer, &len, &isShared, &bufferData);
+  JS::GetArrayBufferLengthAndData(buffer, &len, &isShared, &bufferData);
   CHECK_EQUAL(len, data.len());
   CHECK(bufferData == data.contents());
   CHECK(strcmp(reinterpret_cast<char*>(bufferData), data.asString()) == 0);
 
   buffer = nullptr;
   JS_GC(cx);
   JS_GC(cx);
   CHECK(!data.wasFreed());
@@ -212,30 +214,30 @@ BEGIN_TEST(testArrayBuffer_staticContent
   return true;
 }
 END_TEST(testArrayBuffer_staticContents)
 
 BEGIN_TEST(testArrayBuffer_stealDetachExternal) {
   static const char dataBytes[] = "One two three four";
   ExternalData data(dataBytes);
   JS::RootedObject buffer(
-      cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
-                                    &ExternalData::freeCallback, &data));
+      cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
+                                     &ExternalData::freeCallback, &data));
   CHECK(buffer);
   CHECK(!data.wasFreed());
 
-  void* stolenContents = JS_StealArrayBufferContents(cx, buffer);
+  void* stolenContents = JS::StealArrayBufferContents(cx, buffer);
 
   // External buffers are stealable: the data is copied into freshly allocated
   // memory, and the buffer's data pointer is cleared (immediately freeing the
   // data) and the buffer is marked as detached.
   CHECK(stolenContents != data.contents());
   CHECK(strcmp(reinterpret_cast<char*>(stolenContents), dataBytes) == 0);
   CHECK(data.wasFreed());
-  CHECK(JS_IsDetachedArrayBufferObject(buffer));
+  CHECK(JS::IsDetachedArrayBufferObject(buffer));
 
   JS_free(cx, stolenContents);
   return true;
 }
 END_TEST(testArrayBuffer_stealDetachExternal)
 
 BEGIN_TEST(testArrayBuffer_serializeExternal) {
   JS::RootedValue serializeValue(cx);
@@ -245,18 +247,18 @@ BEGIN_TEST(testArrayBuffer_serializeExte
     serialize = JS_NewFunction(cx, js::testingFunc_serialize, 1, 0, "serialize");
     CHECK(serialize);
 
     serializeValue.setObject(*JS_GetFunctionObject(serialize));
   }
 
   ExternalData data("One two three four");
   JS::RootedObject externalBuffer(
-      cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
-                                    &ExternalData::freeCallback, &data));
+      cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
+                                     &ExternalData::freeCallback, &data));
   CHECK(externalBuffer);
   CHECK(!data.wasFreed());
 
   JS::RootedValue v(cx, JS::ObjectValue(*externalBuffer));
   JS::RootedObject transferMap(cx, JS_NewArrayObject(cx, JS::HandleValueArray(v)));
   CHECK(transferMap);
 
   JS::AutoValueArray<2> args(cx);
--- a/js/src/jsapi-tests/testArrayBufferView.cpp
+++ b/js/src/jsapi-tests/testArrayBufferView.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  */
 
 #include "jsfriendapi.h"
 
+#include "js/ArrayBuffer.h"  // JS::NewArrayBuffer
 #include "jsapi-tests/tests.h"
 #include "vm/ProxyObject.h"
 #include "vm/Realm.h"
 
 #include "vm/Realm-inl.h"
 
 using namespace js;
 
@@ -61,17 +62,17 @@ BEGIN_TEST(testArrayBufferView_type) {
     JS::Rooted<JSObject*> tobj(cx, &tval.toObject());
     CHECK(!JS_IsArrayBufferViewObject(tobj));
   }
 
   return true;
 }
 
 static JSObject* CreateDataView(JSContext* cx) {
-  JS::Rooted<JSObject*> buffer(cx, JS_NewArrayBuffer(cx, 8));
+  JS::Rooted<JSObject*> buffer(cx, JS::NewArrayBuffer(cx, 8));
   if (!buffer) {
     return nullptr;
   }
   return JS_NewDataView(cx, buffer, 0, 8);
 }
 
 template <JSObject* CreateTypedArray(JSContext* cx, uint32_t length),
           size_t Length>
@@ -112,17 +113,17 @@ bool TestViewType(JSContext* cx) {
   JS::RootedObject otherGlobal(
       cx, JS_NewGlobalObject(cx, basicGlobalClass(), nullptr,
                              JS::DontFireOnNewGlobalHook, options));
   CHECK(otherGlobal);
 
   JS::Rooted<JSObject*> buffer(cx);
   {
     AutoRealm ar(cx, otherGlobal);
-    buffer = JS_NewArrayBuffer(cx, 8);
+    buffer = JS::NewArrayBuffer(cx, 8);
     CHECK(buffer);
     CHECK(buffer->as<ArrayBufferObject>().byteLength() == 8);
   }
   CHECK(buffer->compartment() == otherGlobal->compartment());
   CHECK(JS_WrapObject(cx, &buffer));
   CHECK(buffer->compartment() == global->compartment());
 
   JS::Rooted<JSObject*> dataview(cx, JS_NewDataView(cx, buffer, 4, 4));
--- a/js/src/jsapi-tests/testArrayBufferWithUserOwnedContents.cpp
+++ b/js/src/jsapi-tests/testArrayBufferWithUserOwnedContents.cpp
@@ -1,49 +1,53 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  */
 
-#include "jsfriendapi.h"
+#include <stdint.h>  // uint32_t
+
+#include "js/ArrayBuffer.h"  // JS::{DetachArrayBuffer,GetArrayBuffer{ByteLength,Data},IsArrayBufferObject,NewArrayBufferWithUserOwnedContents}
+#include "js/GCAPI.h"        // JS::AutoCheckCannotGC, JS_GC
+#include "js/RootingAPI.h"   // JS::Rooted
 #include "jsapi-tests/tests.h"
 #include "vm/ArrayBufferObject.h"
 
 char testData[] =
     "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
 constexpr size_t testDataLength = sizeof(testData);
 
 static void GC(JSContext* cx) {
   JS_GC(cx);
   // Trigger another to wait for background finalization to end.
   JS_GC(cx);
 }
 
 BEGIN_TEST(testArrayBufferWithUserOwnedContents) {
-  JS::RootedObject obj(
-      cx, JS_NewArrayBufferWithUserOwnedContents(cx, testDataLength, testData));
+  JS::Rooted<JSObject*> obj(cx, JS::NewArrayBufferWithUserOwnedContents(
+                                    cx, testDataLength, testData));
   GC(cx);
   CHECK(VerifyObject(obj, testDataLength));
   GC(cx);
-  JS_DetachArrayBuffer(cx, obj);
+  JS::DetachArrayBuffer(cx, obj);
   GC(cx);
   CHECK(VerifyObject(obj, 0));
 
   return true;
 }
 
 bool VerifyObject(JS::HandleObject obj, uint32_t length) {
   JS::AutoCheckCannotGC nogc;
 
   CHECK(obj);
-  CHECK(JS_IsArrayBufferObject(obj));
-  CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
+  CHECK(JS::IsArrayBufferObject(obj));
+  CHECK_EQUAL(JS::GetArrayBufferByteLength(obj), length);
   bool sharedDummy;
   const char* data = reinterpret_cast<const char*>(
-      JS_GetArrayBufferData(obj, &sharedDummy, nogc));
+      JS::GetArrayBufferData(obj, &sharedDummy, nogc));
   if (length == testDataLength) {
     CHECK(data);
     CHECK(testData == data);
   }
 
   return true;
 }
 
--- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
+++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
@@ -3,16 +3,17 @@
  */
 /* 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/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 
+#include "js/ArrayBuffer.h"  // JS::NewArrayBuffer
 #include "js/RootingAPI.h"
 #include "jsapi-tests/tests.h"
 #include "vm/Runtime.h"
 
 #include "vm/JSContext-inl.h"
 
 // A heap-allocated structure containing one of our barriered pointer wrappers
 // to test.
@@ -175,18 +176,18 @@ END_TEST(testGCHeapPostBarriers)
 
 BEGIN_TEST(testUnbarrieredEquality) {
 #ifdef JS_GC_ZEAL
   AutoLeaveZeal nozeal(cx);
 #endif /* JS_GC_ZEAL */
 
   // Use ArrayBuffers because they have finalizers, which allows using them
   // in ObjectPtr without awkward conversations about nursery allocatability.
-  JS::RootedObject robj(cx, JS_NewArrayBuffer(cx, 20));
-  JS::RootedObject robj2(cx, JS_NewArrayBuffer(cx, 30));
+  JS::RootedObject robj(cx, JS::NewArrayBuffer(cx, 20));
+  JS::RootedObject robj2(cx, JS::NewArrayBuffer(cx, 30));
   cx->runtime()->gc.evictNursery();  // Need tenured objects
 
   // Need some bare pointers to compare against.
   JSObject* obj = robj;
   JSObject* obj2 = robj2;
   const JSObject* constobj = robj;
   const JSObject* constobj2 = robj2;
 
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  */
 
 #include <fcntl.h>
 #include <stdio.h>
 
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::{{Create,Release}MappedArrayBufferContents,DetachArrayBuffer,GetArrayBuffer{ByteLength,Data},Is{,Detached,Mapped}ArrayBufferObject,NewMappedArrayBufferWithContents,StealArrayBufferContents}
 #include "js/StructuredClone.h"
 #include "jsapi-tests/tests.h"
 #include "vm/ArrayBufferObject.h"
 
 #ifdef XP_WIN
 #  include <io.h>
 #  define GET_OS_FD(a) int(_get_osfhandle(a))
 #else
@@ -60,74 +61,75 @@ BEGIN_TEST(testMappedArrayBuffer_bug9451
 
   test_file.remove();
 
   return true;
 }
 
 JSObject* CreateNewObject(const int offset, const int length) {
   int fd = open(test_filename, O_RDONLY);
-  void* ptr = JS_CreateMappedArrayBufferContents(GET_OS_FD(fd), offset, length);
+  void* ptr =
+      JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), offset, length);
   close(fd);
   if (!ptr) {
     return nullptr;
   }
-  JSObject* obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr);
+  JSObject* obj = JS::NewMappedArrayBufferWithContents(cx, length, ptr);
   if (!obj) {
-    JS_ReleaseMappedArrayBufferContents(ptr, length);
+    JS::ReleaseMappedArrayBufferContents(ptr, length);
     return nullptr;
   }
   return obj;
 }
 
 bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length,
                   const bool mapped) {
   JS::AutoCheckCannotGC nogc;
 
   CHECK(obj);
-  CHECK(JS_IsArrayBufferObject(obj));
-  CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
+  CHECK(JS::IsArrayBufferObject(obj));
+  CHECK_EQUAL(JS::GetArrayBufferByteLength(obj), length);
   if (mapped) {
-    CHECK(JS_IsMappedArrayBufferObject(obj));
+    CHECK(JS::IsMappedArrayBufferObject(obj));
   } else {
-    CHECK(!JS_IsMappedArrayBufferObject(obj));
+    CHECK(!JS::IsMappedArrayBufferObject(obj));
   }
   bool sharedDummy;
   const char* data = reinterpret_cast<const char*>(
-      JS_GetArrayBufferData(obj, &sharedDummy, nogc));
+      JS::GetArrayBufferData(obj, &sharedDummy, nogc));
   CHECK(data);
   CHECK(memcmp(data, test_data + offset, length) == 0);
 
   return true;
 }
 
 bool TestCreateObject(uint32_t offset, uint32_t length) {
   JS::RootedObject obj(cx, CreateNewObject(offset, length));
   CHECK(VerifyObject(obj, offset, length, true));
 
   return true;
 }
 
 bool TestReleaseContents() {
   int fd = open(test_filename, O_RDONLY);
-  void* ptr = JS_CreateMappedArrayBufferContents(GET_OS_FD(fd), 0, 12);
+  void* ptr = JS::CreateMappedArrayBufferContents(GET_OS_FD(fd), 0, 12);
   close(fd);
   if (!ptr) {
     return false;
   }
-  JS_ReleaseMappedArrayBufferContents(ptr, 12);
+  JS::ReleaseMappedArrayBufferContents(ptr, 12);
 
   return true;
 }
 
 bool TestDetachObject() {
   JS::RootedObject obj(cx, CreateNewObject(8, 12));
   CHECK(obj);
-  JS_DetachArrayBuffer(cx, obj);
-  CHECK(JS_IsDetachedArrayBufferObject(obj));
+  JS::DetachArrayBuffer(cx, obj);
+  CHECK(JS::IsDetachedArrayBufferObject(obj));
 
   return true;
 }
 
 bool TestCloneObject() {
   JS::RootedObject obj1(cx, CreateNewObject(8, 12));
   CHECK(obj1);
   JSAutoStructuredCloneBuffer cloned_buffer(
@@ -140,20 +142,20 @@ bool TestCloneObject() {
   CHECK(VerifyObject(obj2, 8, 12, false));
 
   return true;
 }
 
 bool TestStealContents() {
   JS::RootedObject obj(cx, CreateNewObject(8, 12));
   CHECK(obj);
-  void* contents = JS_StealArrayBufferContents(cx, obj);
+  void* contents = JS::StealArrayBufferContents(cx, obj);
   CHECK(contents);
   CHECK(memcmp(contents, test_data + 8, 12) == 0);
-  CHECK(JS_IsDetachedArrayBufferObject(obj));
+  CHECK(JS::IsDetachedArrayBufferObject(obj));
 
   return true;
 }
 
 bool TestTransferObject() {
   JS::RootedObject obj1(cx, CreateNewObject(8, 12));
   CHECK(obj1);
   JS::RootedValue v1(cx, JS::ObjectValue(*obj1));
@@ -173,17 +175,17 @@ bool TestTransferObject() {
       JS::StructuredCloneScope::SameProcessSameThread, nullptr, nullptr);
   CHECK(cloned_buffer.write(cx, v1, transferable,
                             JS::CloneDataPolicy().denySharedArrayBuffer(),
                             nullptr, nullptr));
   JS::RootedValue v2(cx);
   CHECK(cloned_buffer.read(cx, &v2, nullptr, nullptr));
   JS::RootedObject obj2(cx, v2.toObjectOrNull());
   CHECK(VerifyObject(obj2, 8, 12, true));
-  CHECK(JS_IsDetachedArrayBufferObject(obj1));
+  CHECK(JS::IsDetachedArrayBufferObject(obj1));
 
   return true;
 }
 
 static void GC(JSContext* cx) {
   JS_GC(cx);
   // Trigger another to wait for background finalization to end.
   JS_GC(cx);
--- a/js/src/jsapi-tests/testStructuredClone.cpp
+++ b/js/src/jsapi-tests/testStructuredClone.cpp
@@ -1,13 +1,14 @@
 /* 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 "builtin/TestingFunctions.h"
+#include "js/ArrayBuffer.h"  // JS::{IsArrayBufferObject,GetArrayBufferLengthAndData,NewExternalArrayBuffer}
 #include "js/StructuredClone.h"
 
 #include "jsapi-tests/tests.h"
 
 using namespace js;
 
 BEGIN_TEST(testStructuredClone_object) {
   JS::RootedObject g1(cx, createGlobal());
@@ -88,18 +89,18 @@ BEGIN_TEST(testStructuredClone_externalA
   CHECK(g2);
 
   JS::RootedValue v1(cx);
 
   {
     JSAutoRealm ar(cx, g1);
 
     JS::RootedObject obj(
-        cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
-                                      &ExternalData::freeCallback, &data));
+        cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
+                                       &ExternalData::freeCallback, &data));
     CHECK(!data.wasFreed());
 
     v1 = JS::ObjectOrNullValue(obj);
     CHECK(v1.isObject());
   }
 
   {
     JSAutoRealm ar(cx, g2);
@@ -109,17 +110,17 @@ BEGIN_TEST(testStructuredClone_externalA
     CHECK(v2.isObject());
 
     JS::RootedObject obj(cx, &v2.toObject());
     CHECK(&v1.toObject() != obj);
 
     uint32_t len;
     bool isShared;
     uint8_t* clonedData;
-    js::GetArrayBufferLengthAndData(obj, &len, &isShared, &clonedData);
+    JS::GetArrayBufferLengthAndData(obj, &len, &isShared, &clonedData);
 
     // The contents of the two array buffers should be equal, but not the
     // same pointer.
     CHECK_EQUAL(len, data.len());
     CHECK(clonedData != data.contents());
     CHECK(strcmp(reinterpret_cast<char*>(clonedData), data.asString()) == 0);
     CHECK(!data.wasFreed());
   }
@@ -141,32 +142,32 @@ BEGIN_TEST(testStructuredClone_externalA
       JS::StructuredCloneScope::SameProcessDifferentThread));
   CHECK(testStructuredCloneCopy(JS::StructuredCloneScope::DifferentProcess));
   return true;
 }
 
 bool testStructuredCloneCopy(JS::StructuredCloneScope scope) {
   ExternalData data("One two three four");
   JS::RootedObject buffer(
-      cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
-                                    &ExternalData::freeCallback, &data));
+      cx, JS::NewExternalArrayBuffer(cx, data.len(), data.contents(),
+                                     &ExternalData::freeCallback, &data));
   CHECK(buffer);
   CHECK(!data.wasFreed());
 
   JS::RootedValue v1(cx, JS::ObjectValue(*buffer));
   JS::RootedValue v2(cx);
   CHECK(clone(scope, v1, &v2));
   JS::RootedObject bufferOut(cx, v2.toObjectOrNull());
   CHECK(bufferOut);
-  CHECK(JS_IsArrayBufferObject(bufferOut));
+  CHECK(JS::IsArrayBufferObject(bufferOut));
 
   uint32_t len;
   bool isShared;
   uint8_t* clonedData;
-  js::GetArrayBufferLengthAndData(bufferOut, &len, &isShared, &clonedData);
+  JS::GetArrayBufferLengthAndData(bufferOut, &len, &isShared, &clonedData);
 
   // Cloning should copy the data, so the contents of the two array buffers
   // should be equal, but not the same pointer.
   CHECK_EQUAL(len, data.len());
   CHECK(clonedData != data.contents());
   CHECK(strcmp(reinterpret_cast<char*>(clonedData), data.asString()) == 0);
   CHECK(!data.wasFreed());
 
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -2,16 +2,18 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  */
 /* 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 "jsfriendapi.h"
 
+#include "js/ArrayBuffer.h"  // JS::{NewArrayBuffer,IsArrayBufferObject,GetArrayBuffer{ByteLength,Data}}
+#include "js/SharedArrayBuffer.h"  // JS::{NewSharedArrayBuffer,GetSharedArrayBufferData}
 #include "jsapi-tests/tests.h"
 #include "vm/Realm.h"
 
 using namespace js;
 
 BEGIN_TEST(testTypedArrays) {
   bool ok = true;
 
@@ -30,28 +32,28 @@ BEGIN_TEST(testTypedArrays) {
        TestPlainTypedArray<JS_NewUint32Array, uint32_t, JS_GetUint32ArrayData>(
            cx) &&
        TestPlainTypedArray<JS_NewFloat32Array, float, JS_GetFloat32ArrayData>(
            cx) &&
        TestPlainTypedArray<JS_NewFloat64Array, double, JS_GetFloat64ArrayData>(
            cx);
 
   size_t nbytes = sizeof(double) * 8;
-  RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
-  CHECK(JS_IsArrayBufferObject(buffer));
+  RootedObject buffer(cx, JS::NewArrayBuffer(cx, nbytes));
+  CHECK(JS::IsArrayBufferObject(buffer));
 
   RootedObject proto(cx);
   JS_GetPrototype(cx, buffer, &proto);
-  CHECK(!JS_IsArrayBufferObject(proto));
+  CHECK(!JS::IsArrayBufferObject(proto));
 
   {
     JS::AutoCheckCannotGC nogc;
     bool isShared;
-    CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
-    memset(JS_GetArrayBufferData(buffer, &isShared, nogc), 1, nbytes);
+    CHECK_EQUAL(JS::GetArrayBufferByteLength(buffer), nbytes);
+    memset(JS::GetArrayBufferData(buffer, &isShared, nogc), 1, nbytes);
     CHECK(!isShared);  // Because ArrayBuffer
   }
 
   ok =
       ok &&
       TestArrayFromBuffer<JS_NewInt8ArrayWithBuffer, JS_NewInt8ArrayFromArray,
                           int8_t, false, JS_GetInt8ArrayData>(cx) &&
       TestArrayFromBuffer<JS_NewUint8ArrayWithBuffer, JS_NewUint8ArrayFromArray,
@@ -149,23 +151,23 @@ template <
 bool TestArrayFromBuffer(JSContext* cx) {
   if (Shared &&
       !cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
     return true;
   }
 
   size_t elts = 8;
   size_t nbytes = elts * sizeof(Element);
-  RootedObject buffer(cx, Shared ? JS_NewSharedArrayBuffer(cx, nbytes)
-                                 : JS_NewArrayBuffer(cx, nbytes));
+  RootedObject buffer(cx, Shared ? JS::NewSharedArrayBuffer(cx, nbytes)
+                                 : JS::NewArrayBuffer(cx, nbytes));
   {
     JS::AutoCheckCannotGC nogc;
     bool isShared;
-    void* data = Shared ? JS_GetSharedArrayBufferData(buffer, &isShared, nogc)
-                        : JS_GetArrayBufferData(buffer, &isShared, nogc);
+    void* data = Shared ? JS::GetSharedArrayBufferData(buffer, &isShared, nogc)
+                        : JS::GetArrayBufferData(buffer, &isShared, nogc);
     CHECK_EQUAL(Shared, isShared);
     memset(data, 1, nbytes);
   }
 
   {
     RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1));
     CHECK(!notArray);
   }
@@ -186,18 +188,18 @@ bool TestArrayFromBuffer(JSContext* cx) 
     Element* data;
     bool isShared;
 
     CHECK(data = GetData(array, &isShared, nogc));
     CHECK_EQUAL(Shared, isShared);
 
     CHECK_EQUAL(
         (void*)data,
-        Shared ? (void*)JS_GetSharedArrayBufferData(buffer, &isShared, nogc)
-               : (void*)JS_GetArrayBufferData(buffer, &isShared, nogc));
+        Shared ? (void*)JS::GetSharedArrayBufferData(buffer, &isShared, nogc)
+               : (void*)JS::GetArrayBufferData(buffer, &isShared, nogc));
     CHECK_EQUAL(Shared, isShared);
 
     CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
   }
 
   RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2));
   CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2);
   CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0u);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2015,120 +2015,16 @@ extern JS_PUBLIC_API bool IsSetObject(JS
 
 /**
  * Assign 'undefined' to all of the object's non-reserved slots. Note: this is
  * done for all slots, regardless of the associated property descriptor.
  */
 JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JSContext* cx,
                                                         JSObject* objArg);
 
-/**
- * Create a new ArrayBuffer with the given |contents|, which may be null only
- * if |nbytes == 0|.  |contents| must be allocated compatible with deallocation
- * by |JS_free|.
- *
- * If and only if an ArrayBuffer is successfully created and returned,
- * ownership of |contents| is transferred to the new ArrayBuffer.
- */
-extern JS_PUBLIC_API JSObject* JS_NewArrayBufferWithContents(JSContext* cx,
-                                                             size_t nbytes,
-                                                             void* contents);
-
-namespace JS {
-
-using BufferContentsFreeFunc = void (*)(void* contents, void* userData);
-
-} /* namespace JS */
-
-/**
- * Create a new ArrayBuffer with the given contents. The contents must not be
- * modified by any other code, internal or external.
- *
- * When the ArrayBuffer is ready to be disposed of, `freeFunc(contents,
- * freeUserData)` will be called to release the ArrayBuffer's reference on the
- * contents.
- *
- * `freeFunc()` must not call any JSAPI functions that could cause a garbage
- * collection.
- *
- * The caller must keep the buffer alive until `freeFunc()` is called, or, if
- * `freeFunc` is null, until the JSRuntime is destroyed.
- *
- * The caller must not access the buffer on other threads. The JS engine will
- * not allow the buffer to be transferred to other threads. If you try to
- * transfer an external ArrayBuffer to another thread, the data is copied to a
- * new malloc buffer. `freeFunc()` must be threadsafe, and may be called from
- * any thread.
- *
- * This allows ArrayBuffers to be used with embedder objects that use reference
- * counting, for example. In that case the caller is responsible
- * for incrementing the reference count before passing the contents to this
- * function. This also allows using non-reference-counted contents that must be
- * freed with some function other than free().
- */
-extern JS_PUBLIC_API JSObject* JS_NewExternalArrayBuffer(
-    JSContext* cx, size_t nbytes, void* contents,
-    JS::BufferContentsFreeFunc freeFunc, void* freeUserData = nullptr);
-
-/**
- * Create a new ArrayBuffer with the given non-null |contents|.
- *
- * Ownership of |contents| remains with the caller: it isn't transferred to the
- * returned ArrayBuffer.  Callers of this function *must* ensure that they
- * perform these two steps, in this order, to properly relinquish ownership of
- * |contents|:
- *
- *   1. Call |JS_DetachArrayBuffer| on the buffer returned by this function.
- *      (|JS_DetachArrayBuffer| is generally fallible, but a call under these
- *      circumstances is guaranteed to succeed.)
- *   2. |contents| may be deallocated or discarded consistent with the manner
- *      in which it was allocated.
- *
- * Do not simply allow the returned buffer to be garbage-collected before
- * deallocating |contents|, because in general there is no way to know *when*
- * an object is fully garbage-collected to the point where this would be safe.
- */
-extern JS_PUBLIC_API JSObject* JS_NewArrayBufferWithUserOwnedContents(
-    JSContext* cx, size_t nbytes, void* contents);
-
-/**
- * Steal the contents of the given ArrayBuffer. The ArrayBuffer has its length
- * set to 0 and its contents array cleared. The caller takes ownership of the
- * return value and must free it or transfer ownership via
- * JS_NewArrayBufferWithContents when done using it.
- */
-extern JS_PUBLIC_API void* JS_StealArrayBufferContents(JSContext* cx,
-                                                       JS::HandleObject obj);
-
-/**
- * Create a new mapped ArrayBuffer with the given memory mapped contents. It
- * must be legal to free the contents pointer by unmapping it. On success,
- * ownership is transferred to the new mapped ArrayBuffer.
- */
-extern JS_PUBLIC_API JSObject* JS_NewMappedArrayBufferWithContents(
-    JSContext* cx, size_t nbytes, void* contents);
-
-/**
- * Create memory mapped ArrayBuffer contents.
- * Caller must take care of closing fd after calling this function.
- */
-extern JS_PUBLIC_API void* JS_CreateMappedArrayBufferContents(int fd,
-                                                              size_t offset,
-                                                              size_t length);
-
-/**
- * Release the allocated resource of mapped ArrayBuffer contents before the
- * object is created.
- * If a new object has been created by JS_NewMappedArrayBufferWithContents()
- * with this content, then JS_DetachArrayBuffer() should be used instead to
- * release the resource used by the object.
- */
-extern JS_PUBLIC_API void JS_ReleaseMappedArrayBufferContents(void* contents,
-                                                              size_t length);
-
 extern JS_PUBLIC_API JS::Value JS_GetReservedSlot(JSObject* obj,
                                                   uint32_t index);
 
 extern JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
                                              const JS::Value& v);
 
 /************************************************************************/
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1571,31 +1571,16 @@ extern JS_FRIEND_API JSObject* JS_NewUin
 extern JS_FRIEND_API JSObject* JS_NewFloat32ArrayWithBuffer(
     JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset,
     int32_t length);
 extern JS_FRIEND_API JSObject* JS_NewFloat64ArrayWithBuffer(
     JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset,
     int32_t length);
 
 /**
- * Create a new SharedArrayBuffer with the given byte length.  This
- * may only be called if
- * JS::RealmCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is
- * true.
- */
-extern JS_FRIEND_API JSObject* JS_NewSharedArrayBuffer(JSContext* cx,
-                                                       uint32_t nbytes);
-
-/**
- * Create a new ArrayBuffer with the given byte length.
- */
-extern JS_FRIEND_API JSObject* JS_NewArrayBuffer(JSContext* cx,
-                                                 uint32_t nbytes);
-
-/**
  * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return
  * false if a security wrapper is encountered that denies the unwrapping. If
  * this test or one of the JS_Is*Array tests succeeds, then it is safe to call
  * the various accessor JSAPI calls defined below.
  */
 extern JS_FRIEND_API bool JS_IsTypedArrayObject(JSObject* obj);
 
 /**
@@ -1643,22 +1628,18 @@ extern JS_FRIEND_API JSObject* UnwrapUin
 extern JS_FRIEND_API JSObject* UnwrapUint8ClampedArray(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapInt16Array(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapUint16Array(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapInt32Array(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapUint32Array(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapFloat32Array(JSObject* obj);
 extern JS_FRIEND_API JSObject* UnwrapFloat64Array(JSObject* obj);
 
-extern JS_FRIEND_API JSObject* UnwrapArrayBuffer(JSObject* obj);
-
 extern JS_FRIEND_API JSObject* UnwrapArrayBufferView(JSObject* obj);
 
-extern JS_FRIEND_API JSObject* UnwrapSharedArrayBuffer(JSObject* obj);
-
 extern JS_FRIEND_API JSObject* UnwrapReadableStream(JSObject* obj);
 
 namespace detail {
 
 extern JS_FRIEND_DATA const Class* const Int8ArrayClassPtr;
 extern JS_FRIEND_DATA const Class* const Uint8ArrayClassPtr;
 extern JS_FRIEND_DATA const Class* const Uint8ClampedArrayClassPtr;
 extern JS_FRIEND_DATA const Class* const Int16ArrayClassPtr;
@@ -1697,39 +1678,18 @@ JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float
 
 // This one isn't inlined because it's rather tricky (by dint of having to deal
 // with a dozen-plus classes and varying slot layouts.
 extern JS_FRIEND_API void GetArrayBufferViewLengthAndData(JSObject* obj,
                                                           uint32_t* length,
                                                           bool* isSharedMemory,
                                                           uint8_t** data);
 
-// This one isn't inlined because there are a bunch of different ArrayBuffer
-// classes that would have to be individually handled here.
-//
-// There is an isShared out argument for API consistency (eases use from DOM).
-// It will always be set to false.
-extern JS_FRIEND_API void GetArrayBufferLengthAndData(JSObject* obj,
-                                                      uint32_t* length,
-                                                      bool* isSharedMemory,
-                                                      uint8_t** data);
-
-// Ditto for SharedArrayBuffer.
-//
-// There is an isShared out argument for API consistency (eases use from DOM).
-// It will always be set to true.
-extern JS_FRIEND_API void GetSharedArrayBufferLengthAndData(
-    JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
-
 }  // namespace js
 
-JS_FRIEND_API uint8_t* JS_GetSharedArrayBufferData(JSObject* obj,
-                                                   bool* isSharedMemory,
-                                                   const JS::AutoRequireNoGC&);
-
 /*
  * Unwrap Typed arrays all at once. Return nullptr without throwing if the
  * object cannot be viewed as the correct typed array, or the typed array
  * object on success, filling both outparameters.
  */
 extern JS_FRIEND_API JSObject* JS_GetObjectAsInt8Array(JSObject* obj,
                                                        uint32_t* length,
                                                        bool* isSharedMemory,
@@ -1763,91 +1723,28 @@ extern JS_FRIEND_API JSObject* JS_GetObj
 extern JS_FRIEND_API JSObject* JS_GetObjectAsFloat64Array(JSObject* obj,
                                                           uint32_t* length,
                                                           bool* isSharedMemory,
                                                           double** data);
 extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBufferView(
     JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
 
 /*
- * Unwrap an ArrayBuffer, return nullptr if it's a different type.
- */
-extern JS_FRIEND_API JSObject* JS_GetObjectAsArrayBuffer(JSObject* obj,
-                                                         uint32_t* length,
-                                                         uint8_t** data);
-
-/*
  * Get the type of elements in a typed array, or MaxTypedArrayViewType if a
  * DataView.
  *
  * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow
  * be known that it would pass such a test: it is an ArrayBufferView or a
  * wrapper of an ArrayBufferView, and the unwrapping will succeed.
  */
 extern JS_FRIEND_API js::Scalar::Type JS_GetArrayBufferViewType(JSObject* obj);
 
 extern JS_FRIEND_API js::Scalar::Type JS_GetSharedArrayBufferViewType(
     JSObject* obj);
 
-/*
- * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
- * return false if a security wrapper is encountered that denies the
- * unwrapping. If this test succeeds, then it is safe to call the various
- * accessor JSAPI calls defined below.
- */
-extern JS_FRIEND_API bool JS_IsArrayBufferObject(JSObject* obj);
-
-extern JS_FRIEND_API bool JS_IsSharedArrayBufferObject(JSObject* obj);
-
-/**
- * Return the available byte length of an ArrayBuffer.
- *
- * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
- * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
- * ArrayBuffer, and the unwrapping will succeed.
- */
-extern JS_FRIEND_API uint32_t JS_GetArrayBufferByteLength(JSObject* obj);
-
-extern JS_FRIEND_API uint32_t JS_GetSharedArrayBufferByteLength(JSObject* obj);
-
-/**
- * Return true if the ArrayBuffer |obj| contains any data, i.e. it is not a
- * detached ArrayBuffer.  (ArrayBuffer.prototype is not an ArrayBuffer.)
- *
- * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
- * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
- * ArrayBuffer, and the unwrapping will succeed.
- */
-extern JS_FRIEND_API bool JS_ArrayBufferHasData(JSObject* obj);
-
-/**
- * Return a pointer to the start of the data referenced by a typed array. The
- * data is still owned by the typed array, and should not be modified on
- * another thread. Furthermore, the pointer can become invalid on GC (if the
- * data is small and fits inside the array's GC header), so callers must take
- * care not to hold on across anything that could GC.
- *
- * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
- * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
- * ArrayBuffer, and the unwrapping will succeed.
- *
- * |*isSharedMemory| will be set to false, the argument is present to simplify
- * its use from code that also interacts with SharedArrayBuffer.
- */
-extern JS_FRIEND_API uint8_t* JS_GetArrayBufferData(JSObject* obj,
-                                                    bool* isSharedMemory,
-                                                    const JS::AutoRequireNoGC&);
-
-/**
- * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
- * may return false if a security wrapper is encountered that denies the
- * unwrapping.
- */
-extern JS_FRIEND_API bool JS_IsMappedArrayBufferObject(JSObject* obj);
-
 /**
  * Return the number of elements in a typed array.
  *
  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
  * be known that it would pass such a test: it is a typed array or a wrapper of
  * a typed array, and the unwrapping will succeed.
  */
 extern JS_FRIEND_API uint32_t JS_GetTypedArrayLength(JSObject* obj);
@@ -1939,34 +1836,16 @@ extern JS_FRIEND_API void* JS_GetArrayBu
  * Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView.
  * This may return a detached buffer.  |obj| must be an object that would
  * return true for JS_IsArrayBufferViewObject().
  */
 extern JS_FRIEND_API JSObject* JS_GetArrayBufferViewBuffer(
     JSContext* cx, JS::HandleObject obj, bool* isSharedMemory);
 
 /**
- * Detach an ArrayBuffer, causing all associated views to no longer refer to
- * the ArrayBuffer's original attached memory.
- *
- * This function throws only if it is provided a non-ArrayBuffer object or if
- * the provided ArrayBuffer is a WASM-backed ArrayBuffer or an ArrayBuffer used
- * in asm.js code.
- */
-extern JS_FRIEND_API bool JS_DetachArrayBuffer(JSContext* cx,
-                                               JS::HandleObject obj);
-
-/**
- * Check whether the obj is a detached ArrayBufferObject. Note that this may
- * return false if a security wrapper is encountered that denies the
- * unwrapping.
- */
-extern JS_FRIEND_API bool JS_IsDetachedArrayBufferObject(JSObject* obj);
-
-/**
  * Create a new DataView using the given buffer for storage. The given buffer
  * must be an ArrayBuffer or SharedArrayBuffer (or a cross-compartment wrapper
  * of either type), and the offset and length must fit within the bounds of the
  * buffer. Currently, nullptr will be returned and an exception will be thrown
  * if these conditions do not hold, but do not depend on that behavior.
  */
 JS_FRIEND_API JSObject* JS_NewDataView(JSContext* cx, JS::HandleObject buffer,
                                        uint32_t byteOffset, int32_t byteLength);
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -112,16 +112,17 @@ EXPORTS += [
     'jsfriendapi.h',
     'jspubtd.h',
     'jstypes.h',
     'perf/jsperf.h',
 ]
 
 EXPORTS.js += [
     '../public/AllocPolicy.h',
+    '../public/ArrayBuffer.h',
     '../public/BuildId.h',
     '../public/CallArgs.h',
     '../public/CallNonGenericMethod.h',
     '../public/CharacterEncoding.h',
     '../public/Class.h',
     '../public/CompilationAndEvaluation.h',
     '../public/CompileOptions.h',
     '../public/ContextOptions.h',
@@ -156,16 +157,17 @@ EXPORTS.js += [
     '../public/ProtoKey.h',
     '../public/Proxy.h',
     '../public/Realm.h',
     '../public/RefCounted.h',
     '../public/RequiredDefines.h',
     '../public/Result.h',
     '../public/RootingAPI.h',
     '../public/SavedFrameAPI.h',
+    '../public/SharedArrayBuffer.h',
     '../public/SliceBudget.h',
     '../public/SourceText.h',
     '../public/StableStringChars.h',
     '../public/Stream.h',
     '../public/StructuredClone.h',
     '../public/SweepingAPI.h',
     '../public/Symbol.h',
     '../public/TraceKind.h',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -79,16 +79,17 @@
 #include "frontend/Parser.h"
 #include "gc/PublicIterators.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/InlinableNatives.h"
 #include "jit/Ion.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitRealm.h"
 #include "jit/shared/CodeGenerator-shared.h"
+#include "js/ArrayBuffer.h"  // JS::{CreateMappedArrayBufferContents,NewMappedArrayBufferWithContents,IsArrayBufferObject,GetArrayBufferLengthAndData}
 #include "js/BuildId.h"  // JS::BuildIdCharVector, JS::SetProcessBuildIdOp
 #include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/ContextOptions.h"  // JS::ContextOptions{,Ref}
 #include "js/Debug.h"
 #include "js/Equality.h"  // JS::SameValue
 #include "js/GCVector.h"
@@ -1531,25 +1532,26 @@ static bool CreateMappedArrayBuffer(JSCo
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_OFFSET_LARGER_THAN_FILESIZE);
       return false;
     }
     size = st.st_size - offset;
   }
 
   void* contents =
-      JS_CreateMappedArrayBufferContents(GET_FD_FROM_FILE(file), offset, size);
+      JS::CreateMappedArrayBufferContents(GET_FD_FROM_FILE(file), offset, size);
   if (!contents) {
     JS_ReportErrorASCII(cx,
                         "failed to allocate mapped array buffer contents "
                         "(possibly due to bad alignment)");
     return false;
   }
 
-  RootedObject obj(cx, JS_NewMappedArrayBufferWithContents(cx, size, contents));
+  RootedObject obj(cx,
+                   JS::NewMappedArrayBufferWithContents(cx, size, contents));
   if (!obj) {
     return false;
   }
 
   args.rval().setObject(*obj);
   return true;
 }
 
@@ -5027,27 +5029,27 @@ static bool BinParse(JSContext* cx, unsi
   if (!args[0].isObject()) {
     const char* typeName = InformalValueTypeName(args[0]);
     JS_ReportErrorASCII(cx, "expected object (ArrayBuffer) to parse, got %s",
                         typeName);
     return false;
   }
 
   RootedObject objBuf(cx, &args[0].toObject());
-  if (!JS_IsArrayBufferObject(objBuf)) {
+  if (!JS::IsArrayBufferObject(objBuf)) {
     const char* typeName = InformalValueTypeName(args[0]);
     JS_ReportErrorASCII(cx, "expected ArrayBuffer to parse, got %s", typeName);
     return false;
   }
 
   uint32_t buf_length = 0;
   bool buf_isSharedMemory = false;
   uint8_t* buf_data = nullptr;
-  GetArrayBufferLengthAndData(objBuf, &buf_length, &buf_isSharedMemory,
-                              &buf_data);
+  JS::GetArrayBufferLengthAndData(objBuf, &buf_length, &buf_isSharedMemory,
+                                  &buf_data);
   MOZ_ASSERT(buf_data);
 
   // Extract argument 2: Options.
 
   if (args.length() >= 2) {
     if (!args[1].isObject()) {
       const char* typeName = InformalValueTypeName(args[1]);
       JS_ReportErrorASCII(cx, "expected object (options) to parse, got %s",
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -31,19 +31,21 @@
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/Array.h"
 #include "builtin/DataViewObject.h"
 #include "gc/Barrier.h"
 #include "gc/FreeOp.h"
 #include "gc/Memory.h"
+#include "js/ArrayBuffer.h"
 #include "js/Conversions.h"
 #include "js/MemoryMetrics.h"
 #include "js/PropertySpec.h"
+#include "js/SharedArrayBuffer.h"
 #include "js/Wrapper.h"
 #include "util/Windows.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/WrapperObject.h"
@@ -1639,33 +1641,33 @@ size_t InnerViewTable::sizeOfExcludingTh
          nurseryKeys.sizeOfExcludingThis(mallocSizeOf);
 }
 
 template <>
 bool JSObject::is<js::ArrayBufferObjectMaybeShared>() const {
   return is<ArrayBufferObject>() || is<SharedArrayBufferObject>();
 }
 
-JS_FRIEND_API uint32_t JS_GetArrayBufferByteLength(JSObject* obj) {
+JS_FRIEND_API uint32_t JS::GetArrayBufferByteLength(JSObject* obj) {
   ArrayBufferObject* aobj = obj->maybeUnwrapAs<ArrayBufferObject>();
   return aobj ? aobj->byteLength() : 0;
 }
 
-JS_FRIEND_API uint8_t* JS_GetArrayBufferData(JSObject* obj,
-                                             bool* isSharedMemory,
-                                             const JS::AutoRequireNoGC&) {
+JS_FRIEND_API uint8_t* JS::GetArrayBufferData(JSObject* obj,
+                                              bool* isSharedMemory,
+                                              const JS::AutoRequireNoGC&) {
   ArrayBufferObject* aobj = obj->maybeUnwrapIf<ArrayBufferObject>();
   if (!aobj) {
     return nullptr;
   }
   *isSharedMemory = false;
   return aobj->dataPointer();
 }
 
-JS_FRIEND_API bool JS_DetachArrayBuffer(JSContext* cx, HandleObject obj) {
+JS_FRIEND_API bool JS::DetachArrayBuffer(JSContext* cx, HandleObject obj) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(obj);
 
   if (!obj->is<ArrayBufferObject>()) {
     JS_ReportErrorASCII(cx, "ArrayBuffer object required");
     return false;
   }
@@ -1677,98 +1679,98 @@ JS_FRIEND_API bool JS_DetachArrayBuffer(
                               JSMSG_WASM_NO_TRANSFER);
     return false;
   }
 
   ArrayBufferObject::detach(cx, buffer);
   return true;
 }
 
-JS_FRIEND_API bool JS_IsDetachedArrayBufferObject(JSObject* obj) {
+JS_FRIEND_API bool JS::IsDetachedArrayBufferObject(JSObject* obj) {
   ArrayBufferObject* aobj = obj->maybeUnwrapIf<ArrayBufferObject>();
   if (!aobj) {
     return false;
   }
 
   return aobj->isDetached();
 }
 
-JS_FRIEND_API JSObject* JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes) {
+JS_FRIEND_API JSObject* JS::NewArrayBuffer(JSContext* cx, uint32_t nbytes) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   return ArrayBufferObject::createZeroed(cx, nbytes);
 }
 
-JS_PUBLIC_API JSObject* JS_NewArrayBufferWithContents(JSContext* cx,
-                                                      size_t nbytes,
-                                                      void* data) {
+JS_PUBLIC_API JSObject* JS::NewArrayBufferWithContents(JSContext* cx,
+                                                       size_t nbytes,
+                                                       void* data) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   MOZ_ASSERT_IF(!data, nbytes == 0);
 
   if (!data) {
     // Don't pass nulled contents to |createForContents|.
     return ArrayBufferObject::createZeroed(cx, 0);
   }
 
   using BufferContents = ArrayBufferObject::BufferContents;
 
   BufferContents contents = BufferContents::createMalloced(data);
   return ArrayBufferObject::createForContents(cx, nbytes, contents);
 }
 
-JS_PUBLIC_API JSObject* JS_NewExternalArrayBuffer(
+JS_PUBLIC_API JSObject* JS::NewExternalArrayBuffer(
     JSContext* cx, size_t nbytes, void* data,
     JS::BufferContentsFreeFunc freeFunc, void* freeUserData) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   MOZ_ASSERT(data);
   MOZ_ASSERT(nbytes > 0);
 
   using BufferContents = ArrayBufferObject::BufferContents;
 
   BufferContents contents =
       BufferContents::createExternal(data, freeFunc, freeUserData);
   return ArrayBufferObject::createForContents(cx, nbytes, contents);
 }
 
-JS_PUBLIC_API JSObject* JS_NewArrayBufferWithUserOwnedContents(JSContext* cx,
-                                                               size_t nbytes,
-                                                               void* data) {
+JS_PUBLIC_API JSObject* JS::NewArrayBufferWithUserOwnedContents(JSContext* cx,
+                                                                size_t nbytes,
+                                                                void* data) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   MOZ_ASSERT(data);
 
   using BufferContents = ArrayBufferObject::BufferContents;
 
   BufferContents contents = BufferContents::createUserOwned(data);
   return ArrayBufferObject::createForContents(cx, nbytes, contents);
 }
 
-JS_FRIEND_API bool JS_IsArrayBufferObject(JSObject* obj) {
+JS_FRIEND_API bool JS::IsArrayBufferObject(JSObject* obj) {
   return obj->canUnwrapAs<ArrayBufferObject>();
 }
 
-JS_FRIEND_API bool JS_ArrayBufferHasData(JSObject* obj) {
+JS_FRIEND_API bool JS::ArrayBufferHasData(JSObject* obj) {
   return !obj->unwrapAs<ArrayBufferObject>().isDetached();
 }
 
-JS_FRIEND_API JSObject* js::UnwrapArrayBuffer(JSObject* obj) {
+JS_FRIEND_API JSObject* JS::UnwrapArrayBuffer(JSObject* obj) {
   return obj->maybeUnwrapIf<ArrayBufferObject>();
 }
 
-JS_FRIEND_API JSObject* js::UnwrapSharedArrayBuffer(JSObject* obj) {
+JS_FRIEND_API JSObject* JS::UnwrapSharedArrayBuffer(JSObject* obj) {
   return obj->maybeUnwrapIf<SharedArrayBufferObject>();
 }
 
-JS_PUBLIC_API void* JS_StealArrayBufferContents(JSContext* cx,
-                                                HandleObject objArg) {
+JS_PUBLIC_API void* JS::StealArrayBufferContents(JSContext* cx,
+                                                 HandleObject objArg) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(objArg);
 
   JSObject* obj = CheckedUnwrapStatic(objArg);
   if (!obj) {
     ReportAccessDenied(cx);
     return nullptr;
@@ -1792,64 +1794,64 @@ JS_PUBLIC_API void* JS_StealArrayBufferC
                               JSMSG_WASM_NO_TRANSFER);
     return nullptr;
   }
 
   AutoRealm ar(cx, buffer);
   return ArrayBufferObject::stealMallocedContents(cx, buffer);
 }
 
-JS_PUBLIC_API JSObject* JS_NewMappedArrayBufferWithContents(JSContext* cx,
-                                                            size_t nbytes,
-                                                            void* data) {
+JS_PUBLIC_API JSObject* JS::NewMappedArrayBufferWithContents(JSContext* cx,
+                                                             size_t nbytes,
+                                                             void* data) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
 
   MOZ_ASSERT(data);
 
   using BufferContents = ArrayBufferObject::BufferContents;
 
   BufferContents contents = BufferContents::createMapped(data);
   return ArrayBufferObject::createForContents(cx, nbytes, contents);
 }
 
-JS_PUBLIC_API void* JS_CreateMappedArrayBufferContents(int fd, size_t offset,
-                                                       size_t length) {
+JS_PUBLIC_API void* JS::CreateMappedArrayBufferContents(int fd, size_t offset,
+                                                        size_t length) {
   return ArrayBufferObject::createMappedContents(fd, offset, length).data();
 }
 
-JS_PUBLIC_API void JS_ReleaseMappedArrayBufferContents(void* contents,
-                                                       size_t length) {
+JS_PUBLIC_API void JS::ReleaseMappedArrayBufferContents(void* contents,
+                                                        size_t length) {
   gc::DeallocateMappedContent(contents, length);
 }
 
-JS_FRIEND_API bool JS_IsMappedArrayBufferObject(JSObject* obj) {
+JS_FRIEND_API bool JS::IsMappedArrayBufferObject(JSObject* obj) {
   ArrayBufferObject* aobj = obj->maybeUnwrapIf<ArrayBufferObject>();
   if (!aobj) {
     return false;
   }
 
   return aobj->isMapped();
 }
 
-JS_FRIEND_API JSObject* JS_GetObjectAsArrayBuffer(JSObject* obj,
-                                                  uint32_t* length,
-                                                  uint8_t** data) {
+JS_FRIEND_API JSObject* JS::GetObjectAsArrayBuffer(JSObject* obj,
+                                                   uint32_t* length,
+                                                   uint8_t** data) {
   ArrayBufferObject* aobj = obj->maybeUnwrapIf<ArrayBufferObject>();
   if (!aobj) {
     return nullptr;
   }
 
   *length = aobj->byteLength();
   *data = aobj->dataPointer();
 
   return aobj;
 }
 
-JS_FRIEND_API void js::GetArrayBufferLengthAndData(JSObject* obj,
+JS_FRIEND_API void JS::GetArrayBufferLengthAndData(JSObject* obj,
                                                    uint32_t* length,
                                                    bool* isSharedMemory,
                                                    uint8_t** data) {
   MOZ_ASSERT(IsArrayBuffer(obj));
   *length = AsArrayBuffer(obj).byteLength();
   *data = AsArrayBuffer(obj).dataPointer();
   *isSharedMemory = false;
 }
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_ArrayBufferObject_h
 #define vm_ArrayBufferObject_h
 
 #include "mozilla/Maybe.h"
 
 #include "builtin/TypedObjectConstants.h"
+#include "js/ArrayBuffer.h"
 #include "js/GCHashTable.h"
 #include "vm/JSObject.h"
 #include "vm/Runtime.h"
 #include "vm/SharedMem.h"
 #include "wasm/WasmTypes.h"
 
 namespace js {
 
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Atomics.h"
 #include "mozilla/CheckedInt.h"
 
 #include "jsfriendapi.h"
 
 #include "gc/FreeOp.h"
 #include "jit/AtomicOperations.h"
 #include "js/PropertySpec.h"
+#include "js/SharedArrayBuffer.h"
 #include "js/Wrapper.h"
 #include "vm/SharedMem.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmTypes.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
@@ -404,46 +405,45 @@ bool js::IsSharedArrayBuffer(JSObject* o
   return o->is<SharedArrayBufferObject>();
 }
 
 SharedArrayBufferObject& js::AsSharedArrayBuffer(HandleObject obj) {
   MOZ_ASSERT(IsSharedArrayBuffer(obj));
   return obj->as<SharedArrayBufferObject>();
 }
 
-JS_FRIEND_API uint32_t JS_GetSharedArrayBufferByteLength(JSObject* obj) {
+JS_FRIEND_API uint32_t JS::GetSharedArrayBufferByteLength(JSObject* obj) {
   auto* aobj = obj->maybeUnwrapAs<SharedArrayBufferObject>();
   return aobj ? aobj->byteLength() : 0;
 }
 
-JS_FRIEND_API void js::GetSharedArrayBufferLengthAndData(JSObject* obj,
+JS_FRIEND_API void JS::GetSharedArrayBufferLengthAndData(JSObject* obj,
                                                          uint32_t* length,
                                                          bool* isSharedMemory,
                                                          uint8_t** data) {
   MOZ_ASSERT(obj->is<SharedArrayBufferObject>());
   *length = obj->as<SharedArrayBufferObject>().byteLength();
   *data = obj->as<SharedArrayBufferObject>().dataPointerShared().unwrap(
       /*safe - caller knows*/);
   *isSharedMemory = true;
 }
 
-JS_FRIEND_API JSObject* JS_NewSharedArrayBuffer(JSContext* cx,
-                                                uint32_t nbytes) {
+JS_FRIEND_API JSObject* JS::NewSharedArrayBuffer(JSContext* cx,
+                                                 uint32_t nbytes) {
   MOZ_ASSERT(cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled());
 
   MOZ_ASSERT(nbytes <= INT32_MAX);
   return SharedArrayBufferObject::New(cx, nbytes, /* proto = */ nullptr);
 }
 
-JS_FRIEND_API bool JS_IsSharedArrayBufferObject(JSObject* obj) {
+JS_FRIEND_API bool JS::IsSharedArrayBufferObject(JSObject* obj) {
   return obj->canUnwrapAs<SharedArrayBufferObject>();
 }
 
-JS_FRIEND_API uint8_t* JS_GetSharedArrayBufferData(JSObject* obj,
-                                                   bool* isSharedMemory,
-                                                   const JS::AutoRequireNoGC&) {
+JS_FRIEND_API uint8_t* JS::GetSharedArrayBufferData(
+    JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&) {
   auto* aobj = obj->maybeUnwrapAs<SharedArrayBufferObject>();
   if (!aobj) {
     return nullptr;
   }
   *isSharedMemory = true;
   return aobj->dataPointerShared().unwrap(/*safe - caller knows*/);
 }
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -38,18 +38,20 @@
 #include <memory>
 #include <utility>
 
 #include "jsapi.h"
 #include "jsdate.h"
 
 #include "builtin/DataViewObject.h"
 #include "builtin/MapObject.h"
+#include "js/ArrayBuffer.h"  // JS::{ArrayBufferHasData,DetachArrayBuffer,IsArrayBufferObject,New{,Mapped}ArrayBufferWithContents,ReleaseMappedArrayBufferContents}
 #include "js/Date.h"
 #include "js/GCHashTable.h"
+#include "js/SharedArrayBuffer.h"  // JS::IsSharedArrayBufferObject
 #include "js/Wrapper.h"
 #include "vm/BigIntType.h"
 #include "vm/JSContext.h"
 #include "vm/RegExpObject.h"
 #include "vm/SavedFrame.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
@@ -976,17 +978,17 @@ void JSStructuredCloneData::discardTrans
 
     if (ownership < JS::SCTAG_TMO_FIRST_OWNED) {
       continue;
     }
 
     if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
       js_free(content);
     } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
-      JS_ReleaseMappedArrayBufferContents(content, extraData);
+      JS::ReleaseMappedArrayBufferContents(content, extraData);
     } else if (freeTransfer) {
       freeTransfer(tag, JS::TransferableOwnership(ownership), content,
                    extraData, closure_);
     } else {
       MOZ_ASSERT(false, "unknown ownership");
     }
   }
 }
@@ -1665,23 +1667,23 @@ bool JSStructuredCloneWriter::startWrite
         RegExpShared* re = RegExpToShared(context(), obj);
         if (!re) {
           return false;
         }
         return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) &&
                writeString(SCTAG_STRING, re->getSource());
       }
       case ESClass::ArrayBuffer: {
-        if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) {
+        if (JS::IsArrayBufferObject(obj) && JS::ArrayBufferHasData(obj)) {
           return writeArrayBuffer(obj);
         }
         break;
       }
       case ESClass::SharedArrayBuffer:
-        if (JS_IsSharedArrayBufferObject(obj)) {
+        if (JS::IsSharedArrayBufferObject(obj)) {
           return writeSharedArrayBuffer(obj);
         }
         break;
       case ESClass::Date: {
         RootedValue unboxed(context());
         if (!Unbox(context(), obj, &unboxed)) {
           return false;
         }
@@ -1857,17 +1859,17 @@ bool JSStructuredCloneWriter::transferOw
           return false;
         }
 
         // Must refresh the point iterator after its collection has
         // been modified.
         point = out.iter();
         point += pointOffset;
 
-        if (!JS_DetachArrayBuffer(cx, arrayBuffer)) {
+        if (!JS::DetachArrayBuffer(cx, arrayBuffer)) {
           return false;
         }
       } else {
         size_t nbytes = arrayBuffer->byteLength();
 
         using BufferContents = ArrayBufferObject::BufferContents;
 
         BufferContents bufContents =
@@ -2695,19 +2697,19 @@ bool JSStructuredCloneReader::readTransf
         ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
         return false;
       }
 
       size_t nbytes = extraData;
       MOZ_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA ||
                  data == JS::SCTAG_TMO_MAPPED_DATA);
       if (data == JS::SCTAG_TMO_ALLOC_DATA) {
-        obj = JS_NewArrayBufferWithContents(cx, nbytes, content);
+        obj = JS::NewArrayBufferWithContents(cx, nbytes, content);
       } else if (data == JS::SCTAG_TMO_MAPPED_DATA) {
-        obj = JS_NewMappedArrayBufferWithContents(cx, nbytes, content);
+        obj = JS::NewMappedArrayBufferWithContents(cx, nbytes, content);
       }
     } else if (tag == SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER) {
       auto savedPos = in.tell();
       auto guard = mozilla::MakeScopeExit([&] { in.seekTo(savedPos); });
       in.seekTo(pos);
       in.seekBy(static_cast<size_t>(extraData));
 
       uint32_t tag, data;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -830,28 +830,29 @@ static bool GenerateAndPushTextMask(nsIF
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
       aFillRect, aFrame->PresContext()->AppUnitsPerDevPixel());
 
   // Evaluate required surface size.
   IntRect drawRect =
       RoundedOut(ToRect(sourceCtx->GetClipExtents(gfxContext::eDeviceSpace)));
 
   Matrix currentMatrix = sourceCtx->CurrentMatrix();
-  Matrix maskTransform =
-      currentMatrix * Matrix::Translation(-drawRect.x, -drawRect.y);
-  maskTransform.Invert();
+  Matrix invCurrentMatrix = currentMatrix;
+  invCurrentMatrix.Invert();
+  Matrix maskSurfaceDeviceOffsetTranslation =
+      Matrix::Translation(drawRect.TopLeft());
 
   // Create a mask surface.
   RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
   if (!sourceTarget->CanCreateSimilarDrawTarget(drawRect.Size(),
                                                 SurfaceFormat::A8)) {
     return false;
   }
   RefPtr<DrawTarget> maskDT = sourceTarget->CreateClippedDrawTarget(
-      drawRect.Size(), maskTransform * currentMatrix, SurfaceFormat::A8);
+      drawRect.Size(), maskSurfaceDeviceOffsetTranslation, SurfaceFormat::A8);
   if (!maskDT || !maskDT->IsValid()) {
     return false;
   }
   RefPtr<gfxContext> maskCtx =
       gfxContext::CreatePreservingTransformOrNull(maskDT);
   MOZ_ASSERT(maskCtx);
   maskCtx->SetMatrix(Matrix::Translation(bounds.TopLeft().ToUnknownPoint()) *
                      currentMatrix * Matrix::Translation(-drawRect.TopLeft()));
@@ -859,18 +860,19 @@ static bool GenerateAndPushTextMask(nsIF
   // Shade text shape into mask A8 surface.
   nsLayoutUtils::PaintFrame(
       maskCtx, aFrame, nsRect(nsPoint(0, 0), aFrame->GetSize()),
       NS_RGB(255, 255, 255), nsDisplayListBuilderMode::GENERATE_GLYPH);
 
   // Push the generated mask into aContext, so that the caller can pop and
   // blend with it.
   RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
-  sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0,
-                                   maskSurface, maskTransform);
+  sourceCtx->PushGroupForBlendBack(
+      gfxContentType::COLOR_ALPHA, 1.0, maskSurface,
+      maskSurfaceDeviceOffsetTranslation * invCurrentMatrix);
 
   return true;
 }
 
 /* static */
 void nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(
     Layer* aLayer, nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
     nsIFrame* aFrame, DisplayItemType aType) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-clip-text-scale-ref.html
@@ -0,0 +1,20 @@
+<meta charset="utf-8">
+
+<style>
+  body { overflow:hidden }
+  p {
+  margin: 1em 0;
+  padding: 1.4em;
+  font: 900 1.2em sans-serif;
+  position:absolute;
+  color: rgba(0,0,0,0);
+  background: red;
+  border: black solid 80px;
+  transform: scale(2,0.3);
+  transform-origin: center;
+  left: 330px;
+  top: -75px;
+}
+
+</style>
+<p>█</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-clip-text-scale.html
@@ -0,0 +1,31 @@
+<meta charset="utf-8">
+
+<style>
+  body { overflow: hidden }
+  p {
+  margin: 1em 0;
+  padding: 1.4em;
+  font: 900 1.2em sans-serif;
+  position:absolute;
+  color: rgba(0,0,0,0);
+}
+
+.text {
+  background: red;
+  -webkit-background-clip: text;
+  background-clip: text;
+  transform: scale(20,2);
+  transform-origin: center;
+  left: 400px;
+  }
+.wrapper {
+  border: black solid 80px;
+  transform: scale(2,0.3);
+  transform-origin: center;
+  left: 330px;
+  top: -75px;
+}
+
+</style>
+<p class="text">█</p>
+<p class="wrapper">█</p>
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -180,8 +180,10 @@ skip-if(!cocoaWidget) == background-repe
 
 fuzzy-if(winWidget,0-102,0-2032) fuzzy-if(skiaContent,0-102,0-2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1a.html background-clip-text-1-ref.html # Bug 1392106
 fuzzy-if(winWidget,0-102,0-2032) fuzzy-if(skiaContent,0-102,0-2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1b.html background-clip-text-1-ref.html # Bug 1392106
 fuzzy-if(winWidget,0-102,0-2032) fuzzy-if(skiaContent,0-102,0-2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1c.html background-clip-text-1-ref.html # Bug 1392106
 fuzzy-if(winWidget,0-102,0-2032) fuzzy-if(skiaContent,0-102,0-2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1d.html background-clip-text-1-ref.html # Bug 1392106
 fuzzy-if(winWidget,0-102,0-2032) fuzzy-if(skiaContent,0-102,0-2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1e.html background-clip-text-1-ref.html # Bug 1392106
 
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-2.html background-clip-text-2-ref.html # Bug 1392106
+
+== background-clip-text-scale.html background-clip-text-scale-ref.html
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -85,18 +85,18 @@ already_AddRefed<DrawTarget> nsSVGClipPa
   IntRect bounds = RoundedOut(
       ToRect(aReferenceContext.GetClipExtents(gfxContext::eDeviceSpace)));
   if (bounds.IsEmpty()) {
     // We don't need to create a mask surface, all drawing is clipped anyway.
     return nullptr;
   }
 
   DrawTarget* referenceDT = aReferenceContext.GetDrawTarget();
-  RefPtr<DrawTarget> maskDT =
-      referenceDT->CreateSimilarDrawTarget(bounds.Size(), SurfaceFormat::A8);
+  RefPtr<DrawTarget> maskDT = referenceDT->CreateClippedDrawTarget(
+      bounds.Size(), Matrix::Translation(bounds.TopLeft()), SurfaceFormat::A8);
 
   aOffset = bounds.TopLeft();
 
   return maskDT.forget();
 }
 
 static void ComposeExtraMask(DrawTarget* aTarget, SourceSurface* aExtraMask,
                              const Matrix& aExtraMasksTransform) {
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -533,18 +533,19 @@ static MaskPaintResult CreateAndPaintMas
     paintResult.transparentBlackMask = true;
     return paintResult;
   }
 
   if (!ctx.GetDrawTarget()->CanCreateSimilarDrawTarget(maskSurfaceRect.Size(),
                                                        SurfaceFormat::A8)) {
     return paintResult;
   }
-  RefPtr<DrawTarget> maskDT = ctx.GetDrawTarget()->CreateSimilarDrawTarget(
-      maskSurfaceRect.Size(), SurfaceFormat::A8);
+  RefPtr<DrawTarget> maskDT = ctx.GetDrawTarget()->CreateClippedDrawTarget(
+      maskSurfaceRect.Size(), Matrix::Translation(aParams.maskRect.TopLeft()),
+      SurfaceFormat::A8);
   if (!maskDT || !maskDT->IsValid()) {
     return paintResult;
   }
 
   // We can paint mask along with opacity only if
   // 1. There is only one mask, or
   // 2. No overlap among masks.
   // Collision detect in #2 is not that trivial, we only accept #1 here.
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -79,21 +79,25 @@ already_AddRefed<SourceSurface> nsSVGMas
   } else {
     maskType = aParams.maskMode == StyleMaskMode::Luminance
                    ? NS_STYLE_MASK_TYPE_LUMINANCE
                    : NS_STYLE_MASK_TYPE_ALPHA;
   }
 
   RefPtr<DrawTarget> maskDT;
   if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
-    maskDT = context->GetDrawTarget()->CreateSimilarDrawTarget(
-        maskSurfaceSize, SurfaceFormat::B8G8R8A8);
+    maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
+        maskSurfaceSize,
+        Matrix::Translation(maskSurfaceRect.x, maskSurfaceRect.y),
+        SurfaceFormat::B8G8R8A8);
   } else {
-    maskDT = context->GetDrawTarget()->CreateSimilarDrawTarget(
-        maskSurfaceSize, SurfaceFormat::A8);
+    maskDT = context->GetDrawTarget()->CreateClippedDrawTarget(
+        maskSurfaceSize,
+        Matrix::Translation(maskSurfaceRect.x, maskSurfaceRect.y),
+        SurfaceFormat::A8);
   }
 
   if (!maskDT || !maskDT->IsValid()) {
     return nullptr;
   }
 
   Matrix maskSurfaceMatrix =
       context->CurrentMatrix() *
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1,9 +1,8 @@
-
 /* 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 <cstdlib>
 #include <cerrno>
 #include <deque>
 #include <set>
@@ -75,17 +74,19 @@
 #include "nsXULAppAPI.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptError.h"
 #include "nsPrintfCString.h"
 #include "nsURLHelper.h"
 #include "nsNetUtil.h"
 #include "nsIURLParser.h"
-#include "js/GCAnnotations.h"
+#include "js/ArrayBuffer.h"    // JS::NewArrayBufferWithContents
+#include "js/GCAnnotations.h"  // JS_HAZ_ROOTED
+#include "js/RootingAPI.h"     // JS::{{,Mutable}Handle,Rooted}
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/RTCCertificate.h"
 #include "mozilla/dom/RTCDTMFSenderBinding.h"
 #include "mozilla/dom/RTCDTMFToneChangeEvent.h"
 #include "mozilla/dom/RTCRtpReceiverBinding.h"
 #include "mozilla/dom/RTCRtpSenderBinding.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
 #include "mozilla/dom/RTCPeerConnectionBinding.h"
@@ -1799,17 +1800,17 @@ void PeerConnectionImpl::DumpPacket_m(si
   // else?
   AutoJSAPI jsapi;
   if (!jsapi.Init(GetWindow())) {
     return;
   }
 
   JS::Rooted<JSObject*> jsobj(
       jsapi.cx(),
-      JS_NewArrayBufferWithContents(jsapi.cx(), size, packet.release()));
+      JS::NewArrayBufferWithContents(jsapi.cx(), size, packet.release()));
 
   RootedSpiderMonkeyInterface<ArrayBuffer> arrayBuffer(jsapi.cx());
   if (!arrayBuffer.Init(jsobj)) {
     return;
   }
 
   JSErrorResult jrv;
   pco->OnPacket(level, type, sending, arrayBuffer, jrv);
--- a/netwerk/base/ArrayBufferInputStream.cpp
+++ b/netwerk/base/ArrayBufferInputStream.cpp
@@ -1,18 +1,19 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 <algorithm>
 #include "ArrayBufferInputStream.h"
 #include "nsStreamUtils.h"
-#include "jsapi.h"
-#include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::{GetArrayBuffer{ByteLength,Data},IsArrayBufferObject}
+#include "js/RootingAPI.h"  // JS::{Handle,Rooted}
+#include "js/Value.h"       // JS::Value
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using mozilla::dom::RootingCx;
 
 NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream,
                   nsIInputStream);
 
@@ -22,36 +23,36 @@ ArrayBufferInputStream::ArrayBufferInput
 NS_IMETHODIMP
 ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
                                 uint32_t aByteOffset, uint32_t aLength) {
   NS_ASSERT_OWNINGTHREAD(ArrayBufferInputStream);
 
   if (!aBuffer.isObject()) {
     return NS_ERROR_FAILURE;
   }
-  JS::RootedObject arrayBuffer(RootingCx(), &aBuffer.toObject());
-  if (!JS_IsArrayBufferObject(arrayBuffer)) {
+  JS::Rooted<JSObject *> arrayBuffer(RootingCx(), &aBuffer.toObject());
+  if (!JS::IsArrayBufferObject(arrayBuffer)) {
     return NS_ERROR_FAILURE;
   }
 
-  uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer);
+  uint32_t buflen = JS::GetArrayBufferByteLength(arrayBuffer);
   uint32_t offset = std::min(buflen, aByteOffset);
   uint32_t bufferLength = std::min(buflen - offset, aLength);
 
   mArrayBuffer = mozilla::MakeUniqueFallible<char[]>(bufferLength);
   if (!mArrayBuffer) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mBufferLength = bufferLength;
 
   JS::AutoCheckCannotGC nogc;
   bool isShared;
   char *src =
-      (char *)JS_GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
+      (char *)JS::GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
   memcpy(&mArrayBuffer[0], src, mBufferLength);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArrayBufferInputStream::Close() {
   mClosed = true;
   return NS_OK;
--- a/toolkit/components/osfile/NativeOSFileInternals.cpp
+++ b/toolkit/components/osfile/NativeOSFileInternals.cpp
@@ -31,18 +31,20 @@
 #include "mozilla/UniquePtr.h"
 
 #include "prio.h"
 #include "prerror.h"
 #include "private/pprio.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::GetArrayBufferByteLength,IsArrayBufferObject,NewArrayBufferWithContents,StealArrayBufferContents
 #include "js/Conversions.h"
 #include "js/MemoryFunctions.h"
+#include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "xpcpublic.h"
 
 #include <algorithm>
 #if defined(XP_UNIX)
 #  include <unistd.h>
 #  include <errno.h>
 #  include <fcntl.h>
@@ -351,17 +353,17 @@ nsresult TypedArrayResult::GetCacheableR
   // this would allow us to have several otherwise unrelated
   // ArrayBuffers with the same underlying C buffer. As this would be
   // very unsafe, we need to cache the result once we have it.
 
   const ArrayBufferContents& contents = mContents.get();
   MOZ_ASSERT(contents.data);
 
   JS::Rooted<JSObject*> arrayBuffer(
-      cx, JS_NewArrayBufferWithContents(cx, contents.nbytes, contents.data));
+      cx, JS::NewArrayBufferWithContents(cx, contents.nbytes, contents.data));
   if (!arrayBuffer) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   JS::Rooted<JSObject*> result(
       cx, JS_NewUint8ArrayWithBuffer(cx, arrayBuffer, 0, contents.nbytes));
   if (!result) {
     return NS_ERROR_OUT_OF_MEMORY;
@@ -884,19 +886,19 @@ class DoReadToStringEvent final : public
  * An event implenting writing atomically to a file.
  */
 class DoWriteAtomicEvent : public AbstractDoEvent {
  public:
   /**
    * @param aPath The path of the file.
    */
   DoWriteAtomicEvent(
-      const nsAString& aPath, UniquePtr<char> aBuffer, const uint64_t aBytes,
-      const nsAString& aTmpPath, const nsAString& aBackupTo, const bool aFlush,
-      const bool aNoOverwrite,
+      const nsAString& aPath, UniquePtr<char[], JS::FreePolicy> aBuffer,
+      const uint64_t aBytes, const nsAString& aTmpPath,
+      const nsAString& aBackupTo, const bool aFlush, const bool aNoOverwrite,
       nsMainThreadPtrHandle<nsINativeOSFileSuccessCallback>& aOnSuccess,
       nsMainThreadPtrHandle<nsINativeOSFileErrorCallback>& aOnError)
       : AbstractDoEvent(aOnSuccess, aOnError),
         mPath(aPath),
         mBuffer(std::move(aBuffer)),
         mBytes(aBytes),
         mTmpPath(aTmpPath),
         mBackupTo(aBackupTo),
@@ -1115,17 +1117,17 @@ class DoWriteAtomicEvent : public Abstra
     MOZ_ASSERT(!NS_IsMainThread());
     mResult->Init(aDispatchDate, TimeStamp::Now() - aDispatchDate,
                   aBytesWritten);
     Succeed(mResult.forget());
     return NS_OK;
   }
 
   const nsString mPath;
-  const UniquePtr<char> mBuffer;
+  const UniquePtr<char[], JS::FreePolicy> mBuffer;
   const int32_t mBytes;
   const nsString mTmpPath;
   const nsString mBackupTo;
   const bool mFlush;
   const bool mNoOverwrite;
 
  private:
   RefPtr<Int32Result> mResult;
@@ -1196,35 +1198,35 @@ NativeOSFileInternalsService::Read(const
 NS_IMETHODIMP
 NativeOSFileInternalsService::WriteAtomic(
     const nsAString& aPath, JS::HandleValue aBuffer, JS::HandleValue aOptions,
     nsINativeOSFileSuccessCallback* aOnSuccess,
     nsINativeOSFileErrorCallback* aOnError, JSContext* cx) {
   MOZ_ASSERT(NS_IsMainThread());
   // Extract typed-array/string into buffer. We also need to store the length
   // of the buffer as that may be required if not provided in `aOptions`.
-  UniquePtr<char> buffer;
+  UniquePtr<char[], JS::FreePolicy> buffer;
   int32_t bytes;
 
   // The incoming buffer must be an Object.
   if (!aBuffer.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::RootedObject bufferObject(cx, nullptr);
   if (!JS_ValueToObject(cx, aBuffer, &bufferObject)) {
     return NS_ERROR_FAILURE;
   }
-  if (!JS_IsArrayBufferObject(bufferObject.get())) {
+  if (!JS::IsArrayBufferObject(bufferObject.get())) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  bytes = JS_GetArrayBufferByteLength(bufferObject.get());
+  bytes = JS::GetArrayBufferByteLength(bufferObject.get());
   buffer.reset(
-      static_cast<char*>(JS_StealArrayBufferContents(cx, bufferObject)));
+      static_cast<char*>(JS::StealArrayBufferContents(cx, bufferObject)));
 
   if (!buffer) {
     return NS_ERROR_FAILURE;
   }
 
   // Extract options.
   dom::NativeOSFileWriteAtomicOptions dict;
 
--- a/toolkit/mozapps/extensions/AddonManagerStartup.cpp
+++ b/toolkit/mozapps/extensions/AddonManagerStartup.cpp
@@ -3,16 +3,17 @@
  * 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 "AddonManagerStartup.h"
 #include "AddonManagerStartup-inlines.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"
 #include "js/JSON.h"
 #include "js/TracingAPI.h"
 #include "xpcpublic.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Compression.h"
 #include "mozilla/LinkedList.h"
@@ -529,32 +530,32 @@ nsresult AddonManagerStartup::EncodeBlob
 
   result.set(JS::ObjectValue(*obj));
   return NS_OK;
 }
 
 nsresult AddonManagerStartup::DecodeBlob(JS::HandleValue value, JSContext* cx,
                                          JS::MutableHandleValue result) {
   NS_ENSURE_TRUE(value.isObject() &&
-                     JS_IsArrayBufferObject(&value.toObject()) &&
-                     JS_ArrayBufferHasData(&value.toObject()),
+                     JS::IsArrayBufferObject(&value.toObject()) &&
+                     JS::ArrayBufferHasData(&value.toObject()),
                  NS_ERROR_INVALID_ARG);
 
   StructuredCloneData holder;
 
   nsCString data;
   {
     JS::AutoCheckCannotGC nogc;
 
     auto obj = &value.toObject();
     bool isShared;
 
     nsDependentCSubstring lz4(
-        reinterpret_cast<char*>(JS_GetArrayBufferData(obj, &isShared, nogc)),
-        JS_GetArrayBufferByteLength(obj));
+        reinterpret_cast<char*>(JS::GetArrayBufferData(obj, &isShared, nogc)),
+        JS::GetArrayBufferByteLength(obj));
 
     MOZ_TRY_VAR(data, DecodeLZ4(lz4, STRUCTURED_CLONE_MAGIC));
   }
 
   bool ok = holder.CopyExternalData(data.get(), data.Length());
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
   ErrorResult rv;
--- a/toolkit/recordreplay/ipc/ParentGraphics.cpp
+++ b/toolkit/recordreplay/ipc/ParentGraphics.cpp
@@ -5,16 +5,20 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This file has the logic which the middleman process uses to send messages to
 // the UI process with painting data from the child process.
 
 #include "ParentInternal.h"
 
 #include "chrome/common/mach_ipc_mac.h"
+#include "jsapi.h"  // JSAutoRealm
+#include "js/ArrayBuffer.h"  // JS::{DetachArrayBuffer,NewArrayBufferWithUserOwnedContents}
+#include "js/RootingAPI.h"  // JS::Rooted
+#include "js/Value.h"       // JS::{,Object}Value
 #include "mozilla/Assertions.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PTextureChild.h"
@@ -160,32 +164,32 @@ void UpdateGraphicsInUIProcess(const Pai
       memcpy(dst, src, width * 4);
     }
   }
 
   AutoSafeJSContext cx;
   JSAutoRealm ar(cx, xpc::PrivilegedJunkScope());
 
   // Create an ArrayBuffer whose contents are the externally-provided |memory|.
-  JS::RootedObject bufferObject(cx);
+  JS::Rooted<JSObject*> bufferObject(cx);
   bufferObject =
-      JS_NewArrayBufferWithUserOwnedContents(cx, width * height * 4, memory);
+      JS::NewArrayBufferWithUserOwnedContents(cx, width * height * 4, memory);
   MOZ_RELEASE_ASSERT(bufferObject);
 
-  JS::RootedValue buffer(cx, ObjectValue(*bufferObject));
+  JS::Rooted<JS::Value> buffer(cx, JS::ObjectValue(*bufferObject));
 
   // Call into the graphics module to update the canvas it manages.
   if (NS_FAILED(gGraphics->UpdateCanvas(buffer, width, height, hadFailure))) {
     MOZ_CRASH("UpdateGraphicsInUIProcess");
   }
 
   // Manually detach this ArrayBuffer once this update completes, as the
-  // JS_NewArrayBufferWithUserOwnedContents API mandates.  (The API also
+  // JS::NewArrayBufferWithUserOwnedContents API mandates.  (The API also
   // guarantees that this call always succeeds.)
-  MOZ_ALWAYS_TRUE(JS_DetachArrayBuffer(cx, bufferObject));
+  MOZ_ALWAYS_TRUE(JS::DetachArrayBuffer(cx, bufferObject));
 }
 
 static void MaybeTriggerExplicitPaint() {
   if (gLastExplicitPaint &&
       gLastExplicitPaint->mCheckpointId == gLastCheckpoint) {
     UpdateGraphicsInUIProcess(gLastExplicitPaint.get());
   }
 }
--- a/xpcom/io/nsBinaryStream.cpp
+++ b/xpcom/io/nsBinaryStream.cpp
@@ -31,17 +31,20 @@
 #include "nsCRT.h"
 #include "nsString.h"
 #include "nsISerializable.h"
 #include "nsIClassInfo.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIURI.h"       // for NS_IURI_IID
 #include "nsIX509Cert.h"  // for NS_IX509CERT_IID
 
-#include "jsfriendapi.h"
+#include "js/ArrayBuffer.h"  // JS::{GetArrayBuffer{,ByteLength},IsArrayBufferObject}
+#include "js/GCAPI.h"        // JS::AutoCheckCannotGC
+#include "js/RootingAPI.h"  // JS::{Handle,Rooted}
+#include "js/Value.h"       // JS::Value
 
 using mozilla::MakeUnique;
 using mozilla::PodCopy;
 using mozilla::UniquePtr;
 
 already_AddRefed<nsIObjectOutputStream> NS_NewObjectOutputStream(
     nsIOutputStream* aOutputStream) {
   MOZ_ASSERT(aOutputStream);
@@ -766,22 +769,22 @@ nsBinaryInputStream::ReadByteArray(uint3
 
 NS_IMETHODIMP
 nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength,
                                      JS::Handle<JS::Value> aBuffer,
                                      JSContext* aCx, uint32_t* aReadLength) {
   if (!aBuffer.isObject()) {
     return NS_ERROR_FAILURE;
   }
-  JS::RootedObject buffer(aCx, &aBuffer.toObject());
-  if (!JS_IsArrayBufferObject(buffer)) {
+  JS::Rooted<JSObject*> buffer(aCx, &aBuffer.toObject());
+  if (!JS::IsArrayBufferObject(buffer)) {
     return NS_ERROR_FAILURE;
   }
 
-  uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer);
+  uint32_t bufferLength = JS::GetArrayBufferByteLength(buffer);
   if (bufferLength < aLength) {
     return NS_ERROR_FAILURE;
   }
 
   uint32_t bufSize = std::min<uint32_t>(aLength, 4096);
   UniquePtr<char[]> buf = MakeUnique<char[]>(bufSize);
 
   uint32_t pos = 0;
@@ -799,23 +802,23 @@ nsBinaryInputStream::ReadArrayBuffer(uin
     if (bytesRead == 0) {
       break;
     }
 
     // Copy data into actual buffer.
 
     JS::AutoCheckCannotGC nogc;
     bool isShared;
-    if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
+    if (bufferLength != JS::GetArrayBufferByteLength(buffer)) {
       return NS_ERROR_FAILURE;
     }
 
-    char* data =
-        reinterpret_cast<char*>(JS_GetArrayBufferData(buffer, &isShared, nogc));
-    MOZ_ASSERT(!isShared);  // Implied by JS_GetArrayBufferData()
+    char* data = reinterpret_cast<char*>(
+        JS::GetArrayBufferData(buffer, &isShared, nogc));
+    MOZ_ASSERT(!isShared);  // Implied by JS::GetArrayBufferData()
     if (!data) {
       return NS_ERROR_FAILURE;
     }
 
     *aReadLength += bytesRead;
     PodCopy(data + pos, buf.get(), bytesRead);
 
     pos += bytesRead;