Merge mozilla-central to autoland. a=merge CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Tue, 05 Mar 2019 11:30:19 +0200
changeset 520231 79221722fcc6b17019ed84227deb02e85f4bf1e2
parent 520230 e31662ecc9d1aca960b7998ce143dd1df1913af2 (current diff)
parent 520224 78601cacfe69dc8659c3fe7cd3eb94366aa3d680 (diff)
child 520232 adfb56717e82c848a88e8c8fdb4746b966cdca29
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
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
--- 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;