Bug 1485066 - Part 1: Remove JSAutoByteString. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 05 Sep 2018 02:25:42 -0700
changeset 490734 52ae4d84b11e507483430e922d25b2083ad5c73e
parent 490733 9f53dc79984c400b17a8e3ddfa23df67ff7299ca
child 490735 775159907c734fcef22df5b9a26316aa78dad732
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1485066
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1485066 - Part 1: Remove JSAutoByteString. r=Waldo
dom/base/ChromeUtils.cpp
dom/base/nsJSUtils.h
dom/bindings/BindingUtils.h
dom/bindings/CallbackInterface.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/public/AutoByteString.h
js/public/CharacterEncoding.h
js/rust/build.rs
js/rust/src/glue.rs
js/rust/src/jsglue.cpp
js/rust/tests/callback.rs
js/src/builtin/Profilers.cpp
js/src/builtin/ReflectParse.cpp
js/src/builtin/TestingFunctions.cpp
js/src/builtin/TypedObject.cpp
js/src/builtin/intl/Collator.cpp
js/src/builtin/intl/DateTimeFormat.cpp
js/src/builtin/intl/IntlObject.cpp
js/src/builtin/intl/NumberFormat.cpp
js/src/builtin/intl/PluralRules.cpp
js/src/builtin/intl/RelativeTimeFormat.cpp
js/src/ctypes/CTypes.cpp
js/src/ctypes/Library.cpp
js/src/frontend/EmitterScope.cpp
js/src/frontend/Parser.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsexn.cpp
js/src/jsexn.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsnum.cpp
js/src/moz.build
js/src/proxy/ScriptedProxyHandler.cpp
js/src/shell/OSObject.cpp
js/src/shell/js.cpp
js/src/vm/BytecodeUtil.cpp
js/src/vm/Debugger.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/ErrorObject.cpp
js/src/vm/Interpreter.cpp
js/src/vm/JSAtom.cpp
js/src/vm/JSAtom.h
js/src/vm/JSContext.cpp
js/src/vm/JSFunction-inl.h
js/src/vm/JSFunction.cpp
js/src/vm/JSObject.cpp
js/src/vm/NativeObject.cpp
js/src/vm/Probes.cpp
js/src/vm/SavedStacks.cpp
js/src/vm/SavedStacks.h
js/src/vm/Scope.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/StringType.cpp
js/src/vm/StringType.h
js/src/vm/UbiNodeCensus.cpp
js/src/wasm/AsmJS.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/src/XPCThrower.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
toolkit/recordreplay/ipc/JSControl.cpp
tools/fuzzing/messagemanager/MessageManagerFuzzer.cpp
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -1,17 +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: */
 /* 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 "ChromeUtils.h"
 
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/SavedFrameAPI.h"
 #include "jsfriendapi.h"
 #include "WrapperFactory.h"
 
 #include "mozilla/Base64.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/PerformanceMetricsCollector.h"
@@ -462,21 +462,21 @@ namespace module_getter {
     JS::Rooted<JSObject*> thisObj(aCx);
     JS::Rooted<jsid> id(aCx);
     if (!ExtractArgs(aCx, args, &callee, &thisObj, &id)) {
       return false;
     }
 
     JS::Rooted<JSString*> moduleURI(
       aCx, js::GetFunctionNativeReserved(callee, SLOT_URI).toString());
-    JSAutoByteString bytes;
-    if (!bytes.encodeUtf8(aCx, moduleURI)) {
+    JS::UniqueChars bytes = JS_EncodeStringToUTF8(aCx, moduleURI);
+    if (!bytes) {
       return false;
     }
-    nsDependentCString uri(bytes.ptr());
+    nsDependentCString uri(bytes.get());
 
     RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
     MOZ_ASSERT(moduleloader);
 
     JS::Rooted<JSObject*> moduleGlobal(aCx);
     JS::Rooted<JSObject*> moduleExports(aCx);
     nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
     if (NS_FAILED(rv)) {
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -14,17 +14,16 @@
  * the generated code itself.
  */
 
 #include "mozilla/Assertions.h"
 
 #include "GeckoProfiler.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
 #include "js/Conversions.h"
 #include "js/StableStringChars.h"
 #include "nsString.h"
 
 class nsIScriptContext;
 class nsIScriptElement;
 class nsIScriptGlobalObject;
 class nsXBLPrototypeBinding;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3,17 +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/. */
 
 #ifndef mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Wrapper.h"
 #include "js/Conversions.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Alignment.h"
 #include "mozilla/Array.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DeferredFinalize.h"
 #include "mozilla/dom/BindingDeclarations.h"
@@ -1308,22 +1308,22 @@ EnumValueNotFound<false>(JSContext* cx, 
   return true;
 }
 
 template<>
 inline bool
 EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
                         const char* sourceDescription)
 {
-  JSAutoByteString deflated;
-  if (!deflated.encodeUtf8(cx, str)) {
+  JS::UniqueChars deflated = JS_EncodeStringToUTF8(cx, str);
+  if (!deflated) {
     return false;
   }
   return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
-                           deflated.ptr(), type);
+                           deflated.get(), type);
 }
 
 template<typename CharT>
 inline int
 FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
 {
   int i = 0;
   for (const EnumEntry* value = values; value->value; ++value, ++i) {
--- a/dom/bindings/CallbackInterface.cpp
+++ b/dom/bindings/CallbackInterface.cpp
@@ -1,35 +1,35 @@
 /* -*- 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 "mozilla/dom/CallbackInterface.h"
 #include "jsapi.h"
+#include "js/CharacterEncoding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsPrintfCString.h"
 
 namespace mozilla {
 namespace dom {
 
 bool
 CallbackInterface::GetCallableProperty(JSContext* cx, JS::Handle<jsid> aPropId,
                                        JS::MutableHandle<JS::Value> aCallable)
 {
   if (!JS_GetPropertyById(cx, CallbackKnownNotGray(), aPropId, aCallable)) {
     return false;
   }
   if (!aCallable.isObject() ||
       !JS::IsCallable(&aCallable.toObject())) {
-    char* propName =
+    JS::UniqueChars propName =
       JS_EncodeString(cx, JS_FORGET_STRING_FLATNESS(JSID_TO_FLAT_STRING(aPropId)));
-    nsPrintfCString description("Property '%s'", propName);
-    JS_free(cx, propName);
+    nsPrintfCString description("Property '%s'", propName.get());
     ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
     return false;
   }
 
   return true;
 }
 
 } // namespace dom
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -11,17 +11,17 @@
 #endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>     /* for isatty() */
 #endif
 
 #include "base/basictypes.h"
 
 #include "jsapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/SourceBufferHolder.h"
 
 #include "xpcpublic.h"
 
 #include "XPCShellEnvironment.h"
 
 #include "mozilla/XPCOM.h"
@@ -78,20 +78,20 @@ static bool
 Print(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
     for (unsigned i = 0; i < args.length(); i++) {
         JSString *str = JS::ToString(cx, args[i]);
         if (!str)
             return false;
-        JSAutoByteString bytes(cx, str);
+        JS::UniqueChars bytes = JS_EncodeString(cx, str);
         if (!bytes)
             return false;
-        fprintf(stdout, "%s%s", i ? " " : "", bytes.ptr());
+        fprintf(stdout, "%s%s", i ? " " : "", bytes.get());
         fflush(stdout);
     }
     fputc('\n', stdout);
     args.rval().setUndefined();
     return true;
 }
 
 static bool
@@ -114,21 +114,21 @@ Dump(JSContext *cx, unsigned argc, JS::V
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
     if (!args.length())
         return true;
 
     JSString *str = JS::ToString(cx, args[0]);
     if (!str)
         return false;
-    JSAutoByteString bytes(cx, str);
+    JS::UniqueChars bytes = JS_EncodeString(cx, str);
     if (!bytes)
       return false;
 
-    fputs(bytes.ptr(), stdout);
+    fputs(bytes.get(), stdout);
     fflush(stdout);
     return true;
 }
 
 static bool
 Load(JSContext *cx,
      unsigned argc,
      JS::Value *vp)
@@ -142,30 +142,30 @@ Load(JSContext *cx,
         JS_ReportErrorASCII(cx, "Trying to load() into a non-global object");
         return false;
     }
 
     for (unsigned i = 0; i < args.length(); i++) {
         JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[i]));
         if (!str)
             return false;
-        JSAutoByteString filename(cx, str);
+        JS::UniqueChars filename = JS_EncodeString(cx, str);
         if (!filename)
             return false;
-        FILE *file = fopen(filename.ptr(), "r");
+        FILE *file = fopen(filename.get(), "r");
         if (!file) {
-            filename.clear();
-            if (!filename.encodeUtf8(cx, str))
+            filename = JS_EncodeStringToUTF8(cx, str);
+            if (!filename)
                 return false;
-            JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading", filename.ptr());
+            JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading", filename.get());
             return false;
         }
         JS::CompileOptions options(cx);
         options.setUTF8(true)
-               .setFileAndLine(filename.ptr(), 1);
+               .setFileAndLine(filename.get(), 1);
         JS::Rooted<JSScript*> script(cx);
         bool ok = JS::Compile(cx, options, file, &script);
         fclose(file);
         if (!ok)
             return false;
 
         if (!JS_ExecuteScript(cx, script)) {
             return false;
@@ -341,23 +341,23 @@ XPCShellEnvironment::ProcessFile(JSConte
         if (JS_CompileScript(cx, buffer, strlen(buffer), options, &script)) {
             JS::WarningReporter older;
 
             ok = JS_ExecuteScript(cx, script, &result);
             if (ok && !result.isUndefined()) {
                 /* Suppress warnings from JS::ToString(). */
                 older = JS::SetWarningReporter(cx, nullptr);
                 str = JS::ToString(cx, result);
-                JSAutoByteString bytes;
+                JS::UniqueChars bytes;
                 if (str)
-                    bytes.encodeLatin1(cx, str);
+                    bytes = JS_EncodeString(cx, str);
                 JS::SetWarningReporter(cx, older);
 
                 if (!!bytes)
-                    fprintf(stdout, "%s\n", bytes.ptr());
+                    fprintf(stdout, "%s\n", bytes.get());
                 else
                     ok = false;
             }
         }
     } while (!hitEOF && !env->IsQuitting());
 
     fprintf(stdout, "\n");
 }
deleted file mode 100644
--- a/js/public/AutoByteString.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * DEPRECATED functions and classes for heap-allocating copies of a JSString's
- * data.
- */
-
-#ifndef js_AutoByteString_h
-#define js_AutoByteString_h
-
-#include "mozilla/Assertions.h" // MOZ_ASSERT
-#include "mozilla/Attributes.h" // MOZ_RAII, MOZ_GUARD*
-
-#include <string.h> // strlen
-
-#include "jstypes.h" // JS_PUBLIC_API
-
-#include "js/MemoryFunctions.h" // JS_free
-#include "js/RootingAPI.h" // JS::Handle
-#include "js/TypeDecls.h" // JSContext, JSString
-#include "js/Utility.h" // js_free, JS::UniqueChars
-
-/**
- * DEPRECATED
- *
- * Allocate memory sufficient to contain the characters of |str| truncated to
- * Latin-1 and a trailing null terminator, fill the memory with the characters
- * interpreted in that manner plus the null terminator, and return a pointer to
- * the memory.  The memory must be freed using JS_free to avoid leaking.
- *
- * This function *loses information* when it copies the characters of |str| if
- * |str| contains code units greater than 0xFF.  Additionally, users that
- * depend on null-termination will misinterpret the copied characters if |str|
- * contains any nulls.  Avoid using this function if possible, because it will
- * eventually be removed.
- */
-extern JS_PUBLIC_API(char*)
-JS_EncodeString(JSContext* cx, JSString* str);
-
-/**
- * DEPRECATED
- *
- * Same behavior as JS_EncodeString(), but encode into a UTF-8 string.
- *
- * This function *loses information* when it copies the characters of |str| if
- * |str| contains invalid UTF-16: U+FFFD REPLACEMENT CHARACTER will be copied
- * instead.
- *
- * The returned string is also subject to misinterpretation if |str| contains
- * any nulls (which are faithfully transcribed into the returned string, but
- * which will implicitly truncate the string if it's passed to functions that
- * expect null-terminated strings).
- *
- * Avoid using this function if possible, because we'll remove it once we can
- * devise a better API for the task.
- */
-extern JS_PUBLIC_API(char*)
-JS_EncodeStringToUTF8(JSContext* cx, JS::Handle<JSString*> str);
-
-/**
- * DEPRECATED
- *
- * A lightweight RAII helper class around the various JS_Encode* functions
- * above, subject to the same pitfalls noted above.  Avoid using this class if
- * possible, because as with the functions above, it too needs to be replaced
- * with a better, safer API.
- */
-class MOZ_RAII JSAutoByteString final
-{
-  private:
-    char* mBytes;
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-
-  private:
-    JSAutoByteString(const JSAutoByteString& another) = delete;
-    void operator=(const JSAutoByteString& another) = delete;
-
-  public:
-    JSAutoByteString(JSContext* cx, JSString* str
-                     MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : mBytes(JS_EncodeString(cx, str))
-    {
-        MOZ_ASSERT(cx);
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    explicit JSAutoByteString(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
-      : mBytes(nullptr)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-
-    ~JSAutoByteString() {
-        JS_free(nullptr, mBytes);
-    }
-
-    /* Take ownership of the given byte array. */
-    void initBytes(JS::UniqueChars&& bytes) {
-        MOZ_ASSERT(!mBytes);
-        mBytes = bytes.release();
-    }
-
-    char* encodeLatin1(JSContext* cx, JSString* str) {
-        MOZ_ASSERT(!mBytes);
-        MOZ_ASSERT(cx);
-        mBytes = JS_EncodeString(cx, str);
-        return mBytes;
-    }
-
-    char* encodeUtf8(JSContext* cx, JS::Handle<JSString*> str) {
-        MOZ_ASSERT(!mBytes);
-        MOZ_ASSERT(cx);
-        mBytes = JS_EncodeStringToUTF8(cx, str);
-        return mBytes;
-    }
-
-    void clear() {
-        js_free(mBytes);
-        mBytes = nullptr;
-    }
-
-    char* ptr() const {
-        return mBytes;
-    }
-
-    bool operator!() const {
-        return !mBytes;
-    }
-
-    size_t length() const {
-        if (!mBytes)
-            return 0;
-        return strlen(mBytes);
-    }
-};
-
-#endif /* js_AutoByteString_h */
--- a/js/public/CharacterEncoding.h
+++ b/js/public/CharacterEncoding.h
@@ -326,9 +326,46 @@ LossyUTF8CharsToNewLatin1CharsZ(JSContex
 extern JS_PUBLIC_API(bool)
 StringIsASCII(const char* s);
 
 } // namespace JS
 
 inline void JS_free(JS::Latin1CharsZ& ptr) { js_free((void*)ptr.get()); }
 inline void JS_free(JS::UTF8CharsZ& ptr) { js_free((void*)ptr.get()); }
 
+/**
+ * DEPRECATED
+ *
+ * Allocate memory sufficient to contain the characters of |str| truncated to
+ * Latin-1 and a trailing null terminator, fill the memory with the characters
+ * interpreted in that manner plus the null terminator, and return a pointer to
+ * the memory.
+ *
+ * This function *loses information* when it copies the characters of |str| if
+ * |str| contains code units greater than 0xFF.  Additionally, users that
+ * depend on null-termination will misinterpret the copied characters if |str|
+ * contains any nulls.  Avoid using this function if possible, because it will
+ * eventually be removed.
+ */
+extern JS_PUBLIC_API(JS::UniqueChars)
+JS_EncodeString(JSContext* cx, JSString* str);
+
+/**
+ * DEPRECATED
+ *
+ * Same behavior as JS_EncodeString(), but encode into a UTF-8 string.
+ *
+ * This function *loses information* when it copies the characters of |str| if
+ * |str| contains invalid UTF-16: U+FFFD REPLACEMENT CHARACTER will be copied
+ * instead.
+ *
+ * The returned string is also subject to misinterpretation if |str| contains
+ * any nulls (which are faithfully transcribed into the returned string, but
+ * which will implicitly truncate the string if it's passed to functions that
+ * expect null-terminated strings).
+ *
+ * Avoid using this function if possible, because we'll remove it once we can
+ * devise a better API for the task.
+ */
+extern JS_PUBLIC_API(JS::UniqueChars)
+JS_EncodeStringToUTF8(JSContext* cx, JS::Handle<JSString*> str);
+
 #endif /* js_CharacterEncoding_h */
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -314,17 +314,16 @@ const WHITELIST_FUNCTIONS: &'static [&'s
     "JS_DefineProperties",
     "JS_DefineProperty",
     "JS_DefinePropertyById",
     "JS_DefineUCProperty",
     "JS::detail::InitWithFailureDiagnostic",
     "JS_DestroyContext",
     "JS::DisableIncrementalGC",
     "js::Dump.*",
-    "JS_EncodeStringToUTF8",
     "JS::EnterRealm",
     "JS_EnumerateStandardClasses",
     "JS_ErrorFromException",
     "JS_FireOnNewGlobalObject",
     "JS_free",
     "JS_GC",
     "JS_GetArrayBufferData",
     "JS_GetArrayBufferViewType",
--- a/js/rust/src/glue.rs
+++ b/js/rust/src/glue.rs
@@ -335,15 +335,19 @@ extern "C" {
     pub fn DeleteJSAutoStructuredCloneBuffer(buf: *mut JSAutoStructuredCloneBuffer);
     pub fn GetLengthOfJSStructuredCloneData(data: *mut JSStructuredCloneData) -> usize;
     pub fn CopyJSStructuredCloneData(src: *mut JSStructuredCloneData, dest: *mut u8);
     pub fn WriteBytesToJSStructuredCloneData(src: *const u8,
                                              len: usize,
                                              dest: *mut JSStructuredCloneData)
                                              -> bool;
 
+    pub fn JSEncodeStringToUTF8(cx: *mut JSContext,
+                                string: JS::HandleString)
+                                -> *mut ::libc::c_char;
+
     pub fn IsDebugBuild() -> bool;
 }
 
 #[test]
 fn jsglue_cpp_configured_correctly() {
     assert_eq!(cfg!(feature = "debugmozjs"), unsafe { IsDebugBuild() });
 }
--- a/js/rust/src/jsglue.cpp
+++ b/js/rust/src/jsglue.cpp
@@ -10,16 +10,17 @@
 #ifdef JS_DEBUG
 // A hack for MFBT. Guard objects need this to work.
 #define DEBUG 1
 #endif
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/Proxy.h"
+#include "js/CharacterEncoding.h"
 #include "js/Class.h"
 #include "js/MemoryMetrics.h"
 #include "js/Principals.h"
 #include "js/StructuredClone.h"
 #include "js/Wrapper.h"
 #include "assert.h"
 
 struct ProxyTraps {
@@ -915,9 +916,15 @@ bool
 WriteBytesToJSStructuredCloneData(const uint8_t* src, size_t len, JSStructuredCloneData* dest)
 {
     assert(src != nullptr);
     assert(dest != nullptr);
 
     return dest->AppendBytes(reinterpret_cast<const char*>(src), len);
 }
 
+char*
+JSEncodeStringToUTF8(JSContext* cx, JS::HandleString string)
+{
+    return JS_EncodeStringToUTF8(cx, string).release();
+}
+
 } // extern "C"
--- a/js/rust/tests/callback.rs
+++ b/js/rust/tests/callback.rs
@@ -2,21 +2,21 @@
  * 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/. */
 
 #[macro_use]
 extern crate js;
 extern crate libc;
 
 use js::ar::AutoRealm;
+use js::glue::JSEncodeStringToUTF8;
 use js::jsapi::root::JS::CallArgs;
 use js::jsapi::root::JS::RealmOptions;
 use js::jsapi::root::JSContext;
 use js::jsapi::root::JS_DefineFunction;
-use js::jsapi::root::JS_EncodeStringToUTF8;
 use js::jsapi::root::JS_NewGlobalObject;
 use js::jsapi::root::JS_ReportErrorASCII;
 use js::jsapi::root::JS::OnNewGlobalHookOption;
 use js::jsapi::root::JS::Value;
 use js::jsval::UndefinedValue;
 use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
 
 use std::ffi::CStr;
@@ -50,15 +50,15 @@ unsafe extern "C" fn puts(context: *mut 
     if args._base.argc_ != 1 {
         JS_ReportErrorASCII(context, b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char);
         return false;
     }
 
     let arg = args.get(0);
     let js = js::rust::ToString(context, arg);
     rooted!(in(context) let message_root = js);
-    let message = JS_EncodeStringToUTF8(context, message_root.handle());
+    let message = JSEncodeStringToUTF8(context, message_root.handle());
     let message = CStr::from_ptr(message);
     println!("{}", str::from_utf8(message.to_bytes()).unwrap());
 
     args.rval().set(UndefinedValue());
     return true;
 }
--- a/js/src/builtin/Profilers.cpp
+++ b/js/src/builtin/Profilers.cpp
@@ -23,16 +23,17 @@
 #endif
 #endif
 
 #ifdef XP_WIN
 # include <process.h>
 # define getpid _getpid
 #endif
 
+#include "js/CharacterEncoding.h"
 #include "js/Utility.h"
 #include "util/Text.h"
 #include "vm/Probes.h"
 
 #include "vm/JSContext-inl.h"
 
 using namespace js;
 
@@ -198,17 +199,17 @@ RequiredStringArg(JSContext* cx, const C
         return nullptr;
     }
 
     if (!args[argi].isString()) {
         JS_ReportErrorASCII(cx, "%s: invalid arguments (string expected)", caller);
         return nullptr;
     }
 
-    return UniqueChars(JS_EncodeString(cx, args[argi].toString()));
+    return JS_EncodeString(cx, args[argi].toString());
 }
 
 static bool
 StartProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 0) {
         args.rval().setBoolean(JS_StartProfiling(nullptr, getpid()));
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -3389,17 +3389,17 @@ reflect_parse(JSContext* cx, uint32_t ar
             if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
                 return false;
 
             if (!prop.isNullOrUndefined()) {
                 RootedString str(cx, ToString<CanGC>(cx, prop));
                 if (!str)
                     return false;
 
-                filename.reset(JS_EncodeString(cx, str));
+                filename = JS_EncodeString(cx, str);
                 if (!filename)
                     return false;
             }
 
             /* config.line */
             RootedId lineId(cx, NameToId(cx->names().line));
             RootedValue oneValue(cx, Int32Value(1));
             if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -36,17 +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/AutoByteString.h"
+#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/SourceBufferHolder.h"
 #include "js/StableStringChars.h"
 #include "js/StructuredClone.h"
@@ -1409,23 +1409,23 @@ CallFunctionWithAsyncStack(JSContext* cx
     if (!args[2].isString() || args[2].toString()->empty()) {
         JS_ReportErrorASCII(cx, "The third argument should be a non-empty string.");
         return false;
     }
 
     RootedObject function(cx, &args[0].toObject());
     RootedObject stack(cx, &args[1].toObject());
     RootedString asyncCause(cx, args[2].toString());
-    JSAutoByteString utf8Cause;
-    if (!utf8Cause.encodeUtf8(cx, asyncCause)) {
+    UniqueChars utf8Cause = JS_EncodeStringToUTF8(cx, asyncCause);
+    if (!utf8Cause) {
         MOZ_ASSERT(cx->isExceptionPending());
         return false;
     }
 
-    JS::AutoSetAsyncStackForNewCalls sas(cx, stack, utf8Cause.ptr(),
+    JS::AutoSetAsyncStackForNewCalls sas(cx, stack, utf8Cause.get(),
                                          JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT);
     return Call(cx, UndefinedHandleValue, function,
                 JS::HandleValueArray::empty(), args.rval());
 }
 
 static bool
 EnableTrackAllocations(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -2189,26 +2189,26 @@ DumpHeap(JSContext* cx, unsigned argc, V
         }
     }
 
     if (args.length() > i) {
         Value v = args[i];
         if (v.isString()) {
             if (!fuzzingSafe) {
                 RootedString str(cx, v.toString());
-                JSAutoByteString fileNameBytes;
-                if (!fileNameBytes.encodeLatin1(cx, str))
+                UniqueChars fileNameBytes = JS_EncodeString(cx, str);
+                if (!fileNameBytes)
                     return false;
-                const char* fileName = fileNameBytes.ptr();
+                const char* fileName = fileNameBytes.get();
                 dumpFile = fopen(fileName, "w");
                 if (!dumpFile) {
-                    fileNameBytes.clear();
-                    if (!fileNameBytes.encodeUtf8(cx, str))
+                    fileNameBytes = JS_EncodeStringToUTF8(cx, str);
+                    if (!fileNameBytes)
                         return false;
-                    JS_ReportErrorUTF8(cx, "can't open %s", fileNameBytes.ptr());
+                    JS_ReportErrorUTF8(cx, "can't open %s", fileNameBytes.get());
                     return false;
                 }
             }
             ++i;
         }
     }
 
     if (i != args.length()) {
@@ -2741,48 +2741,50 @@ class CloneBufferObject : public NativeO
         js_delete(data());
         setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
     }
 
     static bool
     setCloneBuffer_impl(JSContext* cx, const CallArgs& args) {
         Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
 
-        uint8_t* data = nullptr;
-        UniquePtr<uint8_t[], JS::FreePolicy> dataOwner;
+        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;
-            js::GetArrayBufferLengthAndData(buffer, &nbytes, &isSharedMemory, &data);
+            uint8_t* dataBytes = nullptr;
+            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;
-            data = reinterpret_cast<uint8_t*>(JS_EncodeString(cx, str));
-            if (!data)
+            dataOwner = JS_EncodeString(cx, str);
+            if (!dataOwner)
                 return false;
-            dataOwner.reset(data);
+            data = dataOwner.get();
             nbytes = JS_GetStringLength(str);
         }
 
         if (nbytes == 0 || (nbytes % sizeof(uint64_t) != 0)) {
             JS_ReportErrorASCII(cx, "Invalid length for clonebuffer data");
             return false;
         }
 
         auto buf = js::MakeUnique<JSStructuredCloneData>(JS::StructuredCloneScope::DifferentProcess);
         if (!buf || !buf->Init(nbytes)) {
             ReportOutOfMemory(cx);
             return false;
         }
 
-        MOZ_ALWAYS_TRUE(buf->AppendBytes((const char*)data, nbytes));
+        MOZ_ALWAYS_TRUE(buf->AppendBytes(data, nbytes));
         obj->discard();
         obj->setData(buf.release(), true);
 
         args.rval().setUndefined();
         return true;
     }
 
     static bool
@@ -2909,27 +2911,27 @@ const JSPropertySpec CloneBufferObject::
     JS_PS_END
 };
 
 static mozilla::Maybe<JS::StructuredCloneScope>
 ParseCloneScope(JSContext* cx, HandleString str)
 {
     mozilla::Maybe<JS::StructuredCloneScope> scope;
 
-    JSAutoByteString scopeStr(cx, str);
+    UniqueChars scopeStr = JS_EncodeString(cx, str);
     if (!scopeStr)
         return scope;
 
-    if (strcmp(scopeStr.ptr(), "SameProcessSameThread") == 0)
+    if (strcmp(scopeStr.get(), "SameProcessSameThread") == 0)
         scope.emplace(JS::StructuredCloneScope::SameProcessSameThread);
-    else if (strcmp(scopeStr.ptr(), "SameProcessDifferentThread") == 0)
+    else if (strcmp(scopeStr.get(), "SameProcessDifferentThread") == 0)
         scope.emplace(JS::StructuredCloneScope::SameProcessDifferentThread);
-    else if (strcmp(scopeStr.ptr(), "DifferentProcess") == 0)
+    else if (strcmp(scopeStr.get(), "DifferentProcess") == 0)
         scope.emplace(JS::StructuredCloneScope::DifferentProcess);
-    else if (strcmp(scopeStr.ptr(), "DifferentProcessForIndexedDB") == 0)
+    else if (strcmp(scopeStr.get(), "DifferentProcessForIndexedDB") == 0)
         scope.emplace(JS::StructuredCloneScope::DifferentProcessForIndexedDB);
 
     return scope;
 }
 
 static bool
 Serialize(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -2946,23 +2948,23 @@ Serialize(JSContext* cx, unsigned argc, 
         RootedValue v(cx);
         if (!JS_GetProperty(cx, opts, "SharedArrayBuffer", &v))
             return false;
 
         if (!v.isUndefined()) {
             JSString* str = JS::ToString(cx, v);
             if (!str)
                 return false;
-            JSAutoByteString poli(cx, str);
+            UniqueChars poli = JS_EncodeString(cx, str);
             if (!poli)
                 return false;
 
-            if (strcmp(poli.ptr(), "allow") == 0) {
+            if (strcmp(poli.get(), "allow") == 0) {
                 // default
-            } else if (strcmp(poli.ptr(), "deny") == 0) {
+            } else if (strcmp(poli.get(), "deny") == 0) {
                 policy.denySharedArrayBuffer();
             } else {
                 JS_ReportErrorASCII(cx, "Invalid policy value for 'SharedArrayBuffer'");
                 return false;
             }
         }
 
         if (!JS_GetProperty(cx, opts, "scope", &v))
@@ -4116,39 +4118,39 @@ SetGCCallback(JSContext* cx, unsigned ar
 
     RootedValue v(cx);
     if (!JS_GetProperty(cx, opts, "action", &v))
         return false;
 
     JSString* str = JS::ToString(cx, v);
     if (!str)
         return false;
-    JSAutoByteString action(cx, str);
+    UniqueChars action = JS_EncodeString(cx, str);
     if (!action)
         return false;
 
     int32_t phases = 0;
-    if ((strcmp(action.ptr(), "minorGC") == 0) || (strcmp(action.ptr(), "majorGC") == 0)) {
+    if ((strcmp(action.get(), "minorGC") == 0) || (strcmp(action.get(), "majorGC") == 0)) {
         if (!JS_GetProperty(cx, opts, "phases", &v))
             return false;
         if (v.isUndefined()) {
             phases = (1 << JSGC_END);
         } else {
             JSString* str = JS::ToString(cx, v);
             if (!str)
                 return false;
-            JSAutoByteString phasesStr(cx, str);
+            UniqueChars phasesStr = JS_EncodeString(cx, str);
             if (!phasesStr)
                 return false;
 
-            if (strcmp(phasesStr.ptr(), "begin") == 0)
+            if (strcmp(phasesStr.get(), "begin") == 0)
                 phases = (1 << JSGC_BEGIN);
-            else if (strcmp(phasesStr.ptr(), "end") == 0)
+            else if (strcmp(phasesStr.get(), "end") == 0)
                 phases = (1 << JSGC_END);
-            else if (strcmp(phasesStr.ptr(), "both") == 0)
+            else if (strcmp(phasesStr.get(), "both") == 0)
                 phases = (1 << JSGC_BEGIN) | (1 << JSGC_END);
             else {
                 JS_ReportErrorASCII(cx, "Invalid callback phase");
                 return false;
             }
         }
     }
 
@@ -4159,27 +4161,27 @@ SetGCCallback(JSContext* cx, unsigned ar
     }
 
     if (gcCallback::prevMinorGC) {
         JS_SetGCCallback(cx, nullptr, nullptr);
         js_delete<gcCallback::MinorGC>(gcCallback::prevMinorGC);
         gcCallback::prevMinorGC = nullptr;
     }
 
-    if (strcmp(action.ptr(), "minorGC") == 0) {
+    if (strcmp(action.get(), "minorGC") == 0) {
         auto info = js_new<gcCallback::MinorGC>();
         if (!info) {
             ReportOutOfMemory(cx);
             return false;
         }
 
         info->phases = phases;
         info->active = true;
         JS_SetGCCallback(cx, gcCallback::minorGC, info);
-    } else if (strcmp(action.ptr(), "majorGC") == 0) {
+    } else if (strcmp(action.get(), "majorGC") == 0) {
         if (!JS_GetProperty(cx, opts, "depth", &v))
             return false;
         int32_t depth = 1;
         if (!v.isUndefined()) {
             if (!ToInt32(cx, v, &depth))
                 return false;
         }
         if (depth < 0) {
@@ -4729,21 +4731,21 @@ SetTimeZone(JSContext* cx, unsigned argc
 #if defined(_WIN32)
         return _putenv_s("TZ", "") == 0;
 #else
         return unsetenv("TZ") == 0;
 #endif /* _WIN32 */
     };
 
     if (args[0].isString() && !args[0].toString()->empty()) {
-        JSAutoByteString timeZone;
-        if (!timeZone.encodeLatin1(cx, args[0].toString()))
+        UniqueChars timeZone = JS_EncodeString(cx, args[0].toString());
+        if (!timeZone)
             return false;
 
-        if (!setTimeZone(timeZone.ptr())) {
+        if (!setTimeZone(timeZone.get())) {
             JS_ReportErrorASCII(cx, "Failed to set 'TZ' environment variable");
             return false;
         }
     } else {
         if (!unsetTimeZone()) {
             JS_ReportErrorASCII(cx, "Failed to unset 'TZ' environment variable");
             return false;
         }
@@ -4819,21 +4821,21 @@ SetDefaultLocale(JSContext* cx, unsigned
                             : containsOnlyValidBCP47Characters(str->twoByteChars(nogc), length);
         }
 
         if (!hasValidChars) {
             ReportUsageErrorASCII(cx, callee, "First argument should be BCP47 language tag");
             return false;
         }
 
-        JSAutoByteString locale;
-        if (!locale.encodeLatin1(cx, str))
+        UniqueChars locale = JS_EncodeString(cx, str);
+        if (!locale)
             return false;
 
-        if (!JS_SetDefaultLocale(cx->runtime(), locale.ptr())) {
+        if (!JS_SetDefaultLocale(cx->runtime(), locale.get())) {
             ReportOutOfMemory(cx);
             return false;
         }
     } else {
         JS_ResetDefaultLocale(cx->runtime());
     }
 
     args.rval().setUndefined();
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -7,16 +7,17 @@
 #include "builtin/TypedObject-inl.h"
 
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 
 #include "jsutil.h"
 
 #include "gc/Marking.h"
+#include "js/CharacterEncoding.h"
 #include "js/Vector.h"
 #include "util/StringBuffer.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSFunction.h"
 #include "vm/Realm.h"
 #include "vm/SelfHosting.h"
 #include "vm/StringType.h"
 #include "vm/TypedArrayObject.h"
@@ -1593,17 +1594,17 @@ TypedObject::createZeroed(JSContext* cx,
 
 static bool
 ReportTypedObjTypeError(JSContext* cx,
                         const unsigned errorNumber,
                         HandleTypedObject obj)
 {
     // Serialize type string of obj
     RootedAtom typeReprAtom(cx, &obj->typeDescr().stringRepr());
-    UniqueChars typeReprStr(JS_EncodeStringToUTF8(cx, typeReprAtom));
+    UniqueChars typeReprStr = JS_EncodeStringToUTF8(cx, typeReprAtom);
     if (!typeReprStr)
         return false;
 
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, typeReprStr.get());
     return false;
 }
 
 /* static */ void
@@ -1700,17 +1701,17 @@ ReportPropertyError(JSContext* cx,
                     const unsigned errorNumber,
                     HandleId id)
 {
     RootedValue idVal(cx, IdToValue(id));
     RootedString str(cx, ValueToSource(cx, idVal));
     if (!str)
         return false;
 
-    UniqueChars propName(JS_EncodeStringToUTF8(cx, str));
+    UniqueChars propName = JS_EncodeStringToUTF8(cx, str);
     if (!propName)
         return false;
 
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, propName.get());
     return false;
 }
 
 bool
--- a/js/src/builtin/intl/Collator.cpp
+++ b/js/src/builtin/intl/Collator.cpp
@@ -12,17 +12,17 @@
 
 #include "jsapi.h"
 
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/ScopedICUObject.h"
 #include "builtin/intl/SharedIntlData.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 #include "js/TypeDecls.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/Runtime.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
@@ -195,21 +195,21 @@ js::intl_Collator_availableLocales(JSCon
 
 bool
 js::intl_availableCollations(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
     UErrorCode status = U_ZERO_ERROR;
-    UEnumeration* values = ucol_getKeywordValuesForLocale("co", locale.ptr(), false, &status);
+    UEnumeration* values = ucol_getKeywordValuesForLocale("co", locale.get(), false, &status);
     if (U_FAILURE(status)) {
         ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UEnumeration, uenum_close> toClose(values);
 
     uint32_t count = uenum_count(values, &status);
     if (U_FAILURE(status)) {
@@ -272,17 +272,17 @@ NewUCollator(JSContext* cx, Handle<Colla
     RootedValue value(cx);
 
     RootedObject internals(cx, intl::GetInternalsObject(cx, collator));
     if (!internals)
         return nullptr;
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     // UCollator options with default values.
     UColAttributeValue uStrength = UCOL_DEFAULT;
     UColAttributeValue uCaseLevel = UCOL_OFF;
     UColAttributeValue uAlternate = UCOL_DEFAULT;
     UColAttributeValue uNumeric = UCOL_OFF;
@@ -295,17 +295,17 @@ NewUCollator(JSContext* cx, Handle<Colla
 
     {
         JSLinearString* usage = value.toString()->ensureLinear(cx);
         if (!usage)
             return nullptr;
         if (StringEqualsAscii(usage, "search")) {
             // ICU expects search as a Unicode locale extension on locale.
             // Unicode locale extensions must occur before private use extensions.
-            const char* oldLocale = locale.ptr();
+            const char* oldLocale = locale.get();
             const char* p;
             size_t index;
             size_t localeLen = strlen(oldLocale);
             if ((p = strstr(oldLocale, "-x-")))
                 index = p - oldLocale;
             else
                 index = localeLen;
 
@@ -318,18 +318,17 @@ NewUCollator(JSContext* cx, Handle<Colla
             }
             size_t insertLen = strlen(insert);
             char* newLocale = cx->pod_malloc<char>(localeLen + insertLen + 1);
             if (!newLocale)
                 return nullptr;
             memcpy(newLocale, oldLocale, index);
             memcpy(newLocale + index, insert, insertLen);
             memcpy(newLocale + index + insertLen, oldLocale + index, localeLen - index + 1); // '\0'
-            locale.clear();
-            locale.initBytes(JS::UniqueChars(newLocale));
+            locale = JS::UniqueChars(newLocale);
         } else {
             MOZ_ASSERT(StringEqualsAscii(usage, "sort"));
         }
     }
 
     // We don't need to look at the collation property - it can only be set
     // via the Unicode locale extension and is therefore already set on
     // locale.
@@ -381,17 +380,17 @@ NewUCollator(JSContext* cx, Handle<Colla
             uCaseFirst = UCOL_LOWER_FIRST;
         } else {
             MOZ_ASSERT(StringEqualsAscii(caseFirst, "false"));
             uCaseFirst = UCOL_OFF;
         }
     }
 
     UErrorCode status = U_ZERO_ERROR;
-    UCollator* coll = ucol_open(IcuLocale(locale.ptr()), &status);
+    UCollator* coll = ucol_open(IcuLocale(locale.get()), &status);
     if (U_FAILURE(status)) {
         ReportInternalError(cx);
         return nullptr;
     }
 
     ucol_setAttribute(coll, UCOL_STRENGTH, uStrength, &status);
     ucol_setAttribute(coll, UCOL_CASE_LEVEL, uCaseLevel, &status);
     ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, uAlternate, &status);
--- a/js/src/builtin/intl/DateTimeFormat.cpp
+++ b/js/src/builtin/intl/DateTimeFormat.cpp
@@ -14,17 +14,17 @@
 #include "jsfriendapi.h"
 
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/ScopedICUObject.h"
 #include "builtin/intl/SharedIntlData.h"
 #include "builtin/intl/TimeZoneDataGenerated.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 #include "vm/DateTime.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/Runtime.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
@@ -231,20 +231,20 @@ js::intl_DateTimeFormat_availableLocales
     RootedValue result(cx);
     if (!GetAvailableLocales(cx, udat_countAvailable, udat_getAvailable, &result))
         return false;
     args.rval().set(result);
     return true;
 }
 
 static bool
-DefaultCalendar(JSContext* cx, const JSAutoByteString& locale, MutableHandleValue rval)
+DefaultCalendar(JSContext* cx, const UniqueChars& locale, MutableHandleValue rval)
 {
     UErrorCode status = U_ZERO_ERROR;
-    UCalendar* cal = ucal_open(nullptr, 0, locale.ptr(), UCAL_DEFAULT, &status);
+    UCalendar* cal = ucal_open(nullptr, 0, locale.get(), UCAL_DEFAULT, &status);
 
     // This correctly handles nullptr |cal| when opening failed.
     ScopedICUObject<UCalendar, ucal_close> closeCalendar(cal);
 
     const char* calendar = ucal_getType(cal, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
@@ -278,17 +278,17 @@ const CalendarAlias calendarAliases[] = 
 
 bool
 js::intl_availableCalendars(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     RootedObject calendars(cx, NewDenseEmptyArray(cx));
     if (!calendars)
         return false;
     uint32_t index = 0;
 
@@ -297,17 +297,17 @@ js::intl_availableCalendars(JSContext* c
     if (!DefaultCalendar(cx, locale, &element))
         return false;
 
     if (!DefineDataElement(cx, calendars, index++, element))
         return false;
 
     // Now get the calendars that "would make a difference", i.e., not the default.
     UErrorCode status = U_ZERO_ERROR;
-    UEnumeration* values = ucal_getKeywordValuesForLocale("ca", locale.ptr(), false, &status);
+    UEnumeration* values = ucal_getKeywordValuesForLocale("ca", locale.get(), false, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UEnumeration, uenum_close> toClose(values);
 
     uint32_t count = uenum_count(values, &status);
     if (U_FAILURE(status)) {
@@ -355,17 +355,17 @@ js::intl_availableCalendars(JSContext* c
 
 bool
 js::intl_defaultCalendar(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     return DefaultCalendar(cx, locale, args.rval());
 }
 
 bool
 js::intl_IsValidTimeZoneName(JSContext* cx, unsigned argc, Value* vp)
@@ -522,28 +522,28 @@ js::intl_isDefaultTimeZone(JSContext* cx
 bool
 js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].isString());
     MOZ_ASSERT(args[1].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     AutoStableStringChars skeleton(cx);
     if (!skeleton.initTwoByte(cx, args[1].toString()))
         return false;
 
     mozilla::Range<const char16_t> skelChars = skeleton.twoByteRange();
 
     UErrorCode status = U_ZERO_ERROR;
-    UDateTimePatternGenerator* gen = udatpg_open(IcuLocale(locale.ptr()), &status);
+    UDateTimePatternGenerator* gen = udatpg_open(IcuLocale(locale.get()), &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UDateTimePatternGenerator, udatpg_close> toClose(gen);
 
     JSString* str =
         CallICU(cx, [gen, &skelChars](UChar* chars, uint32_t size, UErrorCode* status) {
@@ -559,17 +559,17 @@ js::intl_patternForSkeleton(JSContext* c
 
 bool
 js::intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 4);
     MOZ_ASSERT(args[0].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     UDateFormatStyle dateStyle = UDAT_NONE;
     UDateFormatStyle timeStyle = UDAT_NONE;
 
     if (args[1].isString()) {
         JSLinearString* dateStyleStr = args[1].toString()->ensureLinear(cx);
@@ -607,17 +607,17 @@ js::intl_patternForStyle(JSContext* cx, 
 
     AutoStableStringChars timeZone(cx);
     if (!timeZone.initTwoByte(cx, args[3].toString()))
         return false;
 
     mozilla::Range<const char16_t> timeZoneChars = timeZone.twoByteRange();
 
     UErrorCode status = U_ZERO_ERROR;
-    UDateFormat* df = udat_open(timeStyle, dateStyle, IcuLocale(locale.ptr()),
+    UDateFormat* df = udat_open(timeStyle, dateStyle, IcuLocale(locale.get()),
                                 timeZoneChars.begin().get(), timeZoneChars.length(),
                                 nullptr, -1, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UDateFormat, udat_close> toClose(df);
 
@@ -640,17 +640,17 @@ NewUDateFormat(JSContext* cx, Handle<Dat
     RootedValue value(cx);
 
     RootedObject internals(cx, intl::GetInternalsObject(cx, dateTimeFormat));
     if (!internals)
        return nullptr;
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     // We don't need to look at calendar and numberingSystem - they can only be
     // set via the Unicode locale extension and are therefore already set on
     // locale.
 
     if (!GetProperty(cx, internals, internals, cx->names().timeZone, &value))
@@ -668,17 +668,17 @@ NewUDateFormat(JSContext* cx, Handle<Dat
     AutoStableStringChars pattern(cx);
     if (!pattern.initTwoByte(cx, value.toString()))
         return nullptr;
 
     mozilla::Range<const char16_t> patternChars = pattern.twoByteRange();
 
     UErrorCode status = U_ZERO_ERROR;
     UDateFormat* df =
-        udat_open(UDAT_PATTERN, UDAT_PATTERN, IcuLocale(locale.ptr()),
+        udat_open(UDAT_PATTERN, UDAT_PATTERN, IcuLocale(locale.get()),
                   timeZoneChars.begin().get(), timeZoneChars.length(),
                   patternChars.begin().get(), patternChars.length(), &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return nullptr;
     }
 
     // ECMAScript requires the Gregorian calendar to be used from the beginning
--- a/js/src/builtin/intl/IntlObject.cpp
+++ b/js/src/builtin/intl/IntlObject.cpp
@@ -16,17 +16,17 @@
 
 #include "builtin/intl/Collator.h"
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/DateTimeFormat.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/NumberFormat.h"
 #include "builtin/intl/PluralRules.h"
 #include "builtin/intl/ScopedICUObject.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Class.h"
 #include "js/StableStringChars.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
@@ -45,24 +45,24 @@ using js::intl::IcuLocale;
 /******************** Intl ********************/
 
 bool
 js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     UErrorCode status = U_ZERO_ERROR;
     const UChar* uTimeZone = nullptr;
     int32_t uTimeZoneLength = 0;
-    UCalendar* cal = ucal_open(uTimeZone, uTimeZoneLength, locale.ptr(), UCAL_DEFAULT, &status);
+    UCalendar* cal = ucal_open(uTimeZone, uTimeZoneLength, locale.get(), UCAL_DEFAULT, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UCalendar, ucal_close> toClose(cal);
 
     RootedObject info(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!info)
@@ -366,18 +366,18 @@ ComputeSingleDisplayName(JSContext* cx, 
 bool
 js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 3);
 
     // 1. Assert: locale is a string.
     RootedString str(cx, args[0].toString());
-    JSAutoByteString locale;
-    if (!locale.encodeUtf8(cx, str))
+    UniqueChars locale = JS_EncodeStringToUTF8(cx, str);
+    if (!locale)
         return false;
 
     // 2. Assert: style is a string.
     DisplayNameStyle dnStyle;
     {
         JSLinearString* style = args[1].toString()->ensureLinear(cx);
         if (!style)
             return false;
@@ -400,27 +400,27 @@ js::intl_ComputeDisplayNames(JSContext* 
     // 4. Let result be ArrayCreate(0).
     RootedArrayObject result(cx, NewDenseUnallocatedArray(cx, keys->length()));
     if (!result)
         return false;
 
     UErrorCode status = U_ZERO_ERROR;
 
     UDateFormat* fmt =
-        udat_open(UDAT_DEFAULT, UDAT_DEFAULT, IcuLocale(locale.ptr()),
+        udat_open(UDAT_DEFAULT, UDAT_DEFAULT, IcuLocale(locale.get()),
         nullptr, 0, nullptr, 0, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UDateFormat, udat_close> datToClose(fmt);
 
     // UDateTimePatternGenerator will be needed for translations of date and
     // time fields like "month", "week", "day" etc.
-    UDateTimePatternGenerator* dtpg = udatpg_open(IcuLocale(locale.ptr()), &status);
+    UDateTimePatternGenerator* dtpg = udatpg_open(IcuLocale(locale.get()), &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
     ScopedICUObject<UDateTimePatternGenerator, udatpg_close> datPgToClose(dtpg);
 
     // 5. For each element of keys,
     RootedString keyValStr(cx);
@@ -456,28 +456,28 @@ js::intl_ComputeDisplayNames(JSContext* 
 }
 
 bool
 js::intl_GetLocaleInfo(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     RootedObject info(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!info)
         return false;
 
     if (!DefineDataProperty(cx, info, cx->names().locale, args[0]))
         return false;
 
-    bool rtl = uloc_isRightToLeft(IcuLocale(locale.ptr()));
+    bool rtl = uloc_isRightToLeft(IcuLocale(locale.get()));
 
     RootedValue dir(cx, StringValue(rtl ? cx->names().rtl : cx->names().ltr));
 
     if (!DefineDataProperty(cx, info, cx->names().direction, dir))
         return false;
 
     args.rval().setObject(*info);
     return true;
--- a/js/src/builtin/intl/NumberFormat.cpp
+++ b/js/src/builtin/intl/NumberFormat.cpp
@@ -15,16 +15,17 @@
 #include <stddef.h>
 #include <stdint.h>
 
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/ScopedICUObject.h"
 #include "ds/Sort.h"
 #include "gc/FreeOp.h"
+#include "js/CharacterEncoding.h"
 #include "js/RootingAPI.h"
 #include "js/StableStringChars.h"
 #include "js/TypeDecls.h"
 #include "vm/JSContext.h"
 #include "vm/SelfHosting.h"
 #include "vm/Stack.h"
 
 #include "vm/JSObject-inl.h"
@@ -208,22 +209,22 @@ js::intl_NumberFormat_availableLocales(J
 
 bool
 js::intl_numberingSystem(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isString());
 
-    JSAutoByteString locale(cx, args[0].toString());
+    UniqueChars locale = JS_EncodeString(cx, args[0].toString());
     if (!locale)
         return false;
 
     UErrorCode status = U_ZERO_ERROR;
-    UNumberingSystem* numbers = unumsys_open(IcuLocale(locale.ptr()), &status);
+    UNumberingSystem* numbers = unumsys_open(IcuLocale(locale.get()), &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return false;
     }
 
     ScopedICUObject<UNumberingSystem, unumsys_close> toClose(numbers);
 
     const char* name = unumsys_getName(numbers);
@@ -250,17 +251,17 @@ NewUNumberFormat(JSContext* cx, Handle<N
     RootedValue value(cx);
 
     RootedObject internals(cx, intl::GetInternalsObject(cx, numberFormat));
     if (!internals)
        return nullptr;
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     // UNumberFormat options with default values
     UNumberFormatStyle uStyle = UNUM_DECIMAL;
     const UChar* uCurrency = nullptr;
     uint32_t uMinimumIntegerDigits = 1;
     uint32_t uMinimumFractionDigits = 0;
@@ -342,17 +343,17 @@ NewUNumberFormat(JSContext* cx, Handle<N
         uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
     }
 
     if (!GetProperty(cx, internals, internals, cx->names().useGrouping, &value))
         return nullptr;
     uUseGrouping = value.toBoolean();
 
     UErrorCode status = U_ZERO_ERROR;
-    UNumberFormat* nf = unum_open(uStyle, nullptr, 0, IcuLocale(locale.ptr()), nullptr, &status);
+    UNumberFormat* nf = unum_open(uStyle, nullptr, 0, IcuLocale(locale.get()), nullptr, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return nullptr;
     }
     ScopedICUObject<UNumberFormat, unum_close> toClose(nf);
 
     if (uCurrency) {
         unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, uCurrency, 3, &status);
--- a/js/src/builtin/intl/PluralRules.cpp
+++ b/js/src/builtin/intl/PluralRules.cpp
@@ -10,17 +10,17 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
 
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/ScopedICUObject.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
@@ -191,17 +191,17 @@ NewUNumberFormatForPluralRules(JSContext
     RootedObject internals(cx, intl::GetInternalsObject(cx, pluralRules));
     if (!internals)
        return nullptr;
 
     RootedValue value(cx);
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     uint32_t uMinimumIntegerDigits = 1;
     uint32_t uMinimumFractionDigits = 0;
     uint32_t uMaximumFractionDigits = 3;
     int32_t uMinimumSignificantDigits = -1;
     int32_t uMaximumSignificantDigits = -1;
@@ -229,17 +229,17 @@ NewUNumberFormatForPluralRules(JSContext
 
         if (!GetProperty(cx, internals, internals, cx->names().maximumFractionDigits, &value))
             return nullptr;
         uMaximumFractionDigits = AssertedCast<uint32_t>(value.toInt32());
     }
 
     UErrorCode status = U_ZERO_ERROR;
     UNumberFormat* nf =
-        unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(locale.ptr()), nullptr, &status);
+        unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(locale.get()), nullptr, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return nullptr;
     }
     ScopedICUObject<UNumberFormat, unum_close> toClose(nf);
 
     if (uMinimumSignificantDigits != -1) {
         unum_setAttribute(nf, UNUM_SIGNIFICANT_DIGITS_USED, true);
@@ -264,17 +264,17 @@ NewUPluralRules(JSContext* cx, Handle<Pl
     RootedObject internals(cx, intl::GetInternalsObject(cx, pluralRules));
     if (!internals)
         return nullptr;
 
     RootedValue value(cx);
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     if (!GetProperty(cx, internals, internals, cx->names().type, &value))
         return nullptr;
 
     UPluralType category;
     {
@@ -286,17 +286,17 @@ NewUPluralRules(JSContext* cx, Handle<Pl
             category = UPLURAL_TYPE_CARDINAL;
         } else {
             MOZ_ASSERT(StringEqualsAscii(type, "ordinal"));
             category = UPLURAL_TYPE_ORDINAL;
         }
     }
 
     UErrorCode status = U_ZERO_ERROR;
-    UPluralRules* pr = uplrules_openForType(IcuLocale(locale.ptr()), category, &status);
+    UPluralRules* pr = uplrules_openForType(IcuLocale(locale.get()), category, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return nullptr;
     }
     return pr;
 }
 
 bool
--- a/js/src/builtin/intl/RelativeTimeFormat.cpp
+++ b/js/src/builtin/intl/RelativeTimeFormat.cpp
@@ -10,17 +10,17 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/FloatingPoint.h"
 
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/intl/ScopedICUObject.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 using mozilla::IsNegativeZero;
@@ -219,17 +219,17 @@ NewURelativeDateTimeFormatter(JSContext*
     RootedObject internals(cx, intl::GetInternalsObject(cx, relativeTimeFormat));
     if (!internals)
         return nullptr;
 
     RootedValue value(cx);
 
     if (!GetProperty(cx, internals, internals, cx->names().locale, &value))
         return nullptr;
-    JSAutoByteString locale(cx, value.toString());
+    UniqueChars locale = JS_EncodeString(cx, value.toString());
     if (!locale)
         return nullptr;
 
     if (!GetProperty(cx, internals, internals, cx->names().style, &value))
         return nullptr;
 
     UDateRelativeDateTimeFormatterStyle relDateTimeStyle;
     {
@@ -244,17 +244,17 @@ NewURelativeDateTimeFormatter(JSContext*
         } else {
             MOZ_ASSERT(StringEqualsAscii(style, "long"));
             relDateTimeStyle = UDAT_STYLE_LONG;
         }
     }
 
     UErrorCode status = U_ZERO_ERROR;
     URelativeDateTimeFormatter* rtf =
-        ureldatefmt_open(IcuLocale(locale.ptr()), nullptr, relDateTimeStyle,
+        ureldatefmt_open(IcuLocale(locale.get()), nullptr, relDateTimeStyle,
                          UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
     if (U_FAILURE(status)) {
         intl::ReportInternalError(cx);
         return nullptr;
     }
     return rtf;
 }
 
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -34,19 +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/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 #include "js/UniquePtr.h"
+#include "js/Utility.h"
 #include "js/Vector.h"
 #include "util/Windows.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 
 #include "vm/JSObject-inl.h"
 
 using namespace std;
@@ -977,30 +978,32 @@ static const JSErrorFormatString*
 GetErrorMessage(void* userRef, const unsigned errorNumber)
 {
   if (0 < errorNumber && errorNumber < CTYPESERR_LIMIT)
     return &ErrorFormatString[errorNumber];
   return nullptr;
 }
 
 static const char*
-EncodeLatin1(JSContext* cx, AutoString& str, JSAutoByteString& bytes)
-{
-  return bytes.encodeLatin1(cx, NewUCString(cx, str.finish()));
+EncodeLatin1(JSContext* cx, AutoString& str, JS::UniqueChars& bytes)
+{
+  bytes = JS_EncodeString(cx, NewUCString(cx, str.finish()));
+  return bytes.get();
 }
 
 static const char*
-CTypesToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes)
+CTypesToSourceForError(JSContext* cx, HandleValue val, JS::UniqueChars& bytes)
 {
   if (val.isObject()) {
       RootedObject obj(cx, &val.toObject());
       if (CType::IsCType(obj) || CData::IsCDataMaybeUnwrap(&obj)) {
           RootedValue v(cx, ObjectValue(*obj));
           RootedString str(cx, JS_ValueToSource(cx, v));
-          return bytes.encodeLatin1(cx, str);
+          bytes = JS_EncodeString(cx, str);
+          return bytes.get();
       }
   }
   return ValueToSourceForError(cx, val, bytes);
 }
 
 static void
 BuildCStyleFunctionTypeSource(JSContext* cx, HandleObject typeObj,
                               HandleString nameStr, unsigned ptrCount,
@@ -1174,63 +1177,63 @@ BuildTypeSource(JSContext* cx, JSObject*
                 AutoString& result);
 
 static bool
 ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
           ConversionType convType,
           HandleObject funObj = nullptr, unsigned argIndex = 0,
           HandleObject arrObj = nullptr, unsigned arrIndex = 0)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   if (arrObj) {
     MOZ_ASSERT(CType::IsCType(arrObj));
 
     switch (CType::GetTypeCode(arrObj)) {
     case TYPE_array: {
       MOZ_ASSERT(!funObj);
 
       char indexStr[16];
       SprintfLiteral(indexStr, "%u", arrIndex);
 
       AutoString arrSource;
-      JSAutoByteString arrBytes;
+      JS::UniqueChars arrBytes;
       BuildTypeSource(cx, arrObj, true, arrSource);
       if (!arrSource)
           return false;
       const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
       if (!arrStr)
         return false;
 
       JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                                  CTYPESMSG_CONV_ERROR_ARRAY,
                                  valStr, indexStr, arrStr);
       break;
     }
     case TYPE_struct: {
       JSFlatString* name = GetFieldName(arrObj, arrIndex);
       MOZ_ASSERT(name);
-      JSAutoByteString nameBytes;
-      const char* nameStr = nameBytes.encodeLatin1(cx, name);
+      JS::UniqueChars nameBytes = JS_EncodeString(cx, name);
+      const char* nameStr = nameBytes.get();
       if (!nameStr)
         return false;
 
       AutoString structSource;
-      JSAutoByteString structBytes;
+      JS::UniqueChars structBytes;
       BuildTypeSource(cx, arrObj, true, structSource);
       if (!structSource)
           return false;
       const char* structStr = EncodeLatin1(cx, structSource, structBytes);
       if (!structStr)
         return false;
 
-      JSAutoByteString posBytes;
+      JS::UniqueChars posBytes;
       const char* posStr;
       if (funObj) {
         AutoString posSource;
         BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
         if (!posSource)
             return false;
         posStr = EncodeLatin1(cx, posSource, posBytes);
         if (!posStr)
@@ -1253,50 +1256,50 @@ ConvError(JSContext* cx, const char* exp
   switch (convType) {
   case ConversionType::Argument: {
     MOZ_ASSERT(funObj);
 
     char indexStr[16];
     SprintfLiteral(indexStr, "%u", argIndex + 1);
 
     AutoString funSource;
-    JSAutoByteString funBytes;
+    JS::UniqueChars funBytes;
     BuildFunctionTypeSource(cx, funObj, funSource);
     if (!funSource)
         return false;
     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
     if (!funStr)
       return false;
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                                CTYPESMSG_CONV_ERROR_ARG,
                                valStr, indexStr, funStr);
     break;
   }
   case ConversionType::Finalizer: {
     MOZ_ASSERT(funObj);
 
     AutoString funSource;
-    JSAutoByteString funBytes;
+    JS::UniqueChars funBytes;
     BuildFunctionTypeSource(cx, funObj, funSource);
     if (!funSource)
         return false;
     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
     if (!funStr)
       return false;
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                                CTYPESMSG_CONV_ERROR_FIN, valStr, funStr);
     break;
   }
   case ConversionType::Return: {
     MOZ_ASSERT(funObj);
 
     AutoString funSource;
-    JSAutoByteString funBytes;
+    JS::UniqueChars funBytes;
     BuildFunctionTypeSource(cx, funObj, funSource);
     if (!funSource)
         return false;
     const char* funStr = EncodeLatin1(cx, funSource, funBytes);
     if (!funStr)
       return false;
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1319,33 +1322,33 @@ static bool
 ConvError(JSContext* cx, HandleObject expectedType, HandleValue actual,
           ConversionType convType,
           HandleObject funObj = nullptr, unsigned argIndex = 0,
           HandleObject arrObj = nullptr, unsigned arrIndex = 0)
 {
   MOZ_ASSERT(CType::IsCType(expectedType));
 
   AutoString expectedSource;
-  JSAutoByteString expectedBytes;
+  JS::UniqueChars expectedBytes;
   BuildTypeSource(cx, expectedType, true, expectedSource);
   if (!expectedSource)
       return false;
   const char* expectedStr = EncodeLatin1(cx, expectedSource, expectedBytes);
   if (!expectedStr)
     return false;
 
   return ConvError(cx, expectedStr, actual, convType, funObj, argIndex,
                    arrObj, arrIndex);
 }
 
 static bool
 ArgumentConvError(JSContext* cx, HandleValue actual, const char* funStr,
                   unsigned argIndex)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   char indexStr[16];
   SprintfLiteral(indexStr, "%u", argIndex + 1);
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1364,28 +1367,28 @@ ArgumentLengthError(JSContext* cx, const
 
 static bool
 ArrayLengthMismatch(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
                     unsigned actualLength, HandleValue actual,
                     ConversionType convType)
 {
   MOZ_ASSERT(arrObj && CType::IsCType(arrObj));
 
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   char expectedLengthStr[16];
   SprintfLiteral(expectedLengthStr, "%u", expectedLength);
   char actualLengthStr[16];
   SprintfLiteral(actualLengthStr, "%u", actualLength);
 
   AutoString arrSource;
-  JSAutoByteString arrBytes;
+  JS::UniqueChars arrBytes;
   BuildTypeSource(cx, arrObj, true, arrSource);
   if (!arrSource)
       return false;
   const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
   if (!arrStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1396,28 +1399,28 @@ ArrayLengthMismatch(JSContext* cx, unsig
 
 static bool
 ArrayLengthOverflow(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
                     unsigned actualLength, HandleValue actual,
                     ConversionType convType)
 {
   MOZ_ASSERT(arrObj && CType::IsCType(arrObj));
 
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   char expectedLengthStr[16];
   SprintfLiteral(expectedLengthStr, "%u", expectedLength);
   char actualLengthStr[16];
   SprintfLiteral(actualLengthStr, "%u", actualLength);
 
   AutoString arrSource;
-  JSAutoByteString arrBytes;
+  JS::UniqueChars arrBytes;
   BuildTypeSource(cx, arrObj, true, arrSource);
   if (!arrSource)
       return false;
   const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
   if (!arrStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1449,18 +1452,18 @@ CannotConstructError(JSContext* cx, cons
   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                             CTYPESMSG_CANNOT_CONSTRUCT, type);
   return false;
 }
 
 static bool
 DuplicateFieldError(JSContext* cx, Handle<JSFlatString*> name)
 {
-  JSAutoByteString nameBytes;
-  const char* nameStr = nameBytes.encodeLatin1(cx, name);
+  JS::UniqueChars nameBytes = JS_EncodeString(cx, name);
+  const char* nameStr = nameBytes.get();
   if (!nameStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_DUPLICATE_FIELD, nameStr);
   return false;
 }
 
@@ -1471,17 +1474,17 @@ EmptyFinalizerCallError(JSContext* cx, c
                             CTYPESMSG_EMPTY_FIN_CALL, funName);
   return false;
 }
 
 static bool
 EmptyFinalizerError(JSContext* cx, ConversionType convType,
                     HandleObject funObj = nullptr, unsigned argIndex = 0)
 {
-  JSAutoByteString posBytes;
+  JS::UniqueChars posBytes;
   const char* posStr;
   if (funObj) {
     AutoString posSource;
     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
     if (!posSource)
         return false;
     posStr = EncodeLatin1(cx, posSource, posBytes);
     if (!posStr)
@@ -1499,36 +1502,36 @@ static bool
 FieldCountMismatch(JSContext* cx,
                    unsigned expectedCount, HandleObject structObj,
                    unsigned actualCount, HandleValue actual,
                    ConversionType convType,
                    HandleObject funObj = nullptr, unsigned argIndex = 0)
 {
   MOZ_ASSERT(structObj && CType::IsCType(structObj));
 
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   AutoString structSource;
-  JSAutoByteString structBytes;
+  JS::UniqueChars structBytes;
   BuildTypeSource(cx, structObj, true, structSource);
   if (!structSource)
       return false;
   const char* structStr = EncodeLatin1(cx, structSource, structBytes);
   if (!structStr)
     return false;
 
   char expectedCountStr[16];
   SprintfLiteral(expectedCountStr, "%u", expectedCount);
   char actualCountStr[16];
   SprintfLiteral(actualCountStr, "%u", actualCount);
 
-  JSAutoByteString posBytes;
+  JS::UniqueChars posBytes;
   const char* posStr;
   if (funObj) {
     AutoString posSource;
     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
     if (!posSource)
         return false;
     posStr = EncodeLatin1(cx, posSource, posBytes);
     if (!posStr)
@@ -1542,127 +1545,127 @@ FieldCountMismatch(JSContext* cx,
                              valStr, structStr, expectedCountStr, actualCountStr,
                              posStr);
   return false;
 }
 
 static bool
 FieldDescriptorCountError(JSContext* cx, HandleValue typeVal, size_t length)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
   if (!valStr)
     return false;
 
   char lengthStr[16];
   SprintfLiteral(lengthStr, "%zu", length);
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_DESC_COUNT, valStr, lengthStr);
   return false;
 }
 
 static bool
 FieldDescriptorNameError(JSContext* cx, HandleId id)
 {
-  JSAutoByteString idBytes;
+  JS::UniqueChars idBytes;
   RootedValue idVal(cx, IdToValue(id));
   const char* propStr = CTypesToSourceForError(cx, idVal, idBytes);
   if (!propStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_DESC_NAME, propStr);
   return false;
 }
 
 static bool
 FieldDescriptorSizeError(JSContext* cx, HandleObject typeObj, HandleId id)
 {
   RootedValue typeVal(cx, ObjectValue(*typeObj));
-  JSAutoByteString typeBytes;
+  JS::UniqueChars typeBytes;
   const char* typeStr = CTypesToSourceForError(cx, typeVal, typeBytes);
   if (!typeStr)
     return false;
 
   RootedString idStr(cx, IdToString(cx, id));
-  JSAutoByteString idBytes;
-  const char* propStr = idBytes.encodeLatin1(cx, idStr);
+  JS::UniqueChars idBytes = JS_EncodeString(cx, idStr);
+  const char* propStr = idBytes.get();
   if (!propStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_DESC_SIZE, typeStr, propStr);
   return false;
 }
 
 static bool
 FieldDescriptorNameTypeError(JSContext* cx, HandleValue typeVal)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_DESC_NAMETYPE, valStr);
   return false;
 }
 
 static bool
 FieldDescriptorTypeError(JSContext* cx, HandleValue poroVal, HandleId id)
 {
-  JSAutoByteString typeBytes;
+  JS::UniqueChars typeBytes;
   const char* typeStr = CTypesToSourceForError(cx, poroVal, typeBytes);
   if (!typeStr)
     return false;
 
   RootedString idStr(cx, IdToString(cx, id));
-  JSAutoByteString idBytes;
-  const char* propStr = idBytes.encodeLatin1(cx, idStr);
+  JS::UniqueChars idBytes = JS_EncodeString(cx, idStr);
+  const char* propStr = idBytes.get();
   if (!propStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_DESC_TYPE, typeStr, propStr);
   return false;
 }
 
 static bool
 FieldMissingError(JSContext* cx, JSObject* typeObj, JSFlatString* name_)
 {
-  JSAutoByteString typeBytes;
+  JS::UniqueChars typeBytes;
   RootedString name(cx, name_);
   RootedValue typeVal(cx, ObjectValue(*typeObj));
   const char* typeStr = CTypesToSourceForError(cx, typeVal, typeBytes);
   if (!typeStr)
     return false;
 
-  JSAutoByteString nameBytes;
-  const char* nameStr = nameBytes.encodeLatin1(cx, name);
+  JS::UniqueChars nameBytes = JS_EncodeString(cx, name);
+  const char* nameStr = nameBytes.get();
   if (!nameStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_FIELD_MISSING, typeStr, nameStr);
   return false;
 }
 
 static bool
 FinalizerSizeError(JSContext* cx, HandleObject funObj, HandleValue actual)
 {
   MOZ_ASSERT(CType::IsCType(funObj));
 
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   AutoString funSource;
-  JSAutoByteString funBytes;
+  JS::UniqueChars funBytes;
   BuildFunctionTypeSource(cx, funObj, funSource);
   if (!funSource)
       return false;
   const char* funStr = EncodeLatin1(cx, funSource, funBytes);
   if (!funStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1672,17 +1675,17 @@ FinalizerSizeError(JSContext* cx, Handle
 
 static bool
 FunctionArgumentLengthMismatch(JSContext* cx,
                                unsigned expectedCount, unsigned actualCount,
                                HandleObject funObj, HandleObject typeObj,
                                bool isVariadic)
 {
   AutoString funSource;
-  JSAutoByteString funBytes;
+  JS::UniqueChars funBytes;
   Value slot = JS_GetReservedSlot(funObj, SLOT_REFERENT);
   if (!slot.isUndefined() && Library::IsLibrary(&slot.toObject())) {
     BuildFunctionTypeSource(cx, funObj, funSource);
   } else {
     BuildFunctionTypeSource(cx, typeObj, funSource);
   }
   if (!funSource)
       return false;
@@ -1703,47 +1706,47 @@ FunctionArgumentLengthMismatch(JSContext
                              actualCountStr);
   return false;
 }
 
 static bool
 FunctionArgumentTypeError(JSContext* cx,
                           uint32_t index, HandleValue typeVal, const char* reason)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, typeVal, valBytes);
   if (!valStr)
     return false;
 
   char indexStr[16];
   SprintfLiteral(indexStr, "%u", index + 1);
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_ARG_TYPE_ERROR,
                              indexStr, reason, valStr);
   return false;
 }
 
 static bool
 FunctionReturnTypeError(JSContext* cx, HandleValue type, const char* reason)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, type, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_RET_TYPE_ERROR, reason, valStr);
   return false;
 }
 
 static bool
 IncompatibleCallee(JSContext* cx, const char* funName, HandleObject actualObj)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   RootedValue val(cx, ObjectValue(*actualObj));
   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_INCOMPATIBLE_CALLEE, funName, valStr);
   return false;
@@ -1757,17 +1760,17 @@ IncompatibleThisProto(JSContext* cx, con
                              CTYPESMSG_INCOMPATIBLE_THIS,
                              funName, actualType);
   return false;
 }
 
 static bool
 IncompatibleThisProto(JSContext* cx, const char* funName, HandleValue actualVal)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actualVal, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_INCOMPATIBLE_THIS_VAL,
                              funName, "incompatible object", valStr);
   return false;
@@ -1781,31 +1784,31 @@ IncompatibleThisType(JSContext* cx, cons
                             funName, actualType);
   return false;
 }
 
 static bool
 IncompatibleThisType(JSContext* cx, const char* funName, const char* actualType,
                      HandleValue actualVal)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actualVal, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_INCOMPATIBLE_THIS_VAL,
                              funName, actualType, valStr);
   return false;
 }
 
 static bool
 InvalidIndexError(JSContext* cx, HandleValue val)
 {
-  JSAutoByteString idBytes;
+  JS::UniqueChars idBytes;
   const char* indexStr = CTypesToSourceForError(cx, val, idBytes);
   if (!indexStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_INVALID_INDEX, indexStr);
   return false;
 }
@@ -1832,73 +1835,73 @@ InvalidIndexRangeError(JSContext* cx, si
 }
 
 static bool
 NonPrimitiveError(JSContext* cx, HandleObject typeObj)
 {
   MOZ_ASSERT(CType::IsCType(typeObj));
 
   AutoString typeSource;
-  JSAutoByteString typeBytes;
+  JS::UniqueChars typeBytes;
   BuildTypeSource(cx, typeObj, true, typeSource);
   if (!typeSource)
       return false;
   const char* typeStr = EncodeLatin1(cx, typeSource, typeBytes);
   if (!typeStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_NON_PRIMITIVE, typeStr);
   return false;
 }
 
 static bool
 NonStringBaseError(JSContext* cx, HandleValue thisVal)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, thisVal, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_NON_STRING_BASE, valStr);
   return false;
 }
 
 static bool
 NullPointerError(JSContext* cx, const char* action, HandleObject obj)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   RootedValue val(cx, ObjectValue(*obj));
   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_NULL_POINTER, action, valStr);
   return false;
 }
 
 static bool
 PropNameNonStringError(JSContext* cx, HandleId id, HandleValue actual,
                        ConversionType convType,
                        HandleObject funObj = nullptr, unsigned argIndex = 0)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
-  JSAutoByteString idBytes;
+  JS::UniqueChars idBytes;
   RootedValue idVal(cx, IdToValue(id));
   const char* propStr = CTypesToSourceForError(cx, idVal, idBytes);
   if (!propStr)
     return false;
 
-  JSAutoByteString posBytes;
+  JS::UniqueChars posBytes;
   const char* posStr;
   if (funObj) {
     AutoString posSource;
     BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
     if (!posSource)
         return false;
     posStr = EncodeLatin1(cx, posSource, posBytes);
     if (!posStr)
@@ -1918,44 +1921,44 @@ SizeOverflow(JSContext* cx, const char* 
   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                             CTYPESMSG_SIZE_OVERFLOW, name, limit);
   return false;
 }
 
 static bool
 TypeError(JSContext* cx, const char* expected, HandleValue actual)
 {
-  JSAutoByteString bytes;
+  JS::UniqueChars bytes;
   const char* src = CTypesToSourceForError(cx, actual, bytes);
   if (!src)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_TYPE_ERROR, expected, src);
   return false;
 }
 
 static bool
 TypeOverflow(JSContext* cx, const char* expected, HandleValue actual)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_TYPE_OVERFLOW, valStr, expected);
   return false;
 }
 
 static bool
 UndefinedSizeCastError(JSContext* cx, HandleObject targetTypeObj)
 {
   AutoString targetTypeSource;
-  JSAutoByteString targetTypeBytes;
+  JS::UniqueChars targetTypeBytes;
   BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
   if (!targetTypeSource)
       return false;
   const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource, targetTypeBytes);
   if (!targetTypeStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
@@ -1964,26 +1967,26 @@ UndefinedSizeCastError(JSContext* cx, Ha
 }
 
 static bool
 SizeMismatchCastError(JSContext* cx,
                       HandleObject sourceTypeObj, HandleObject targetTypeObj,
                       size_t sourceSize, size_t targetSize)
 {
   AutoString sourceTypeSource;
-  JSAutoByteString sourceTypeBytes;
+  JS::UniqueChars sourceTypeBytes;
   BuildTypeSource(cx, sourceTypeObj, true, sourceTypeSource);
   if (!sourceTypeSource)
       return false;
   const char* sourceTypeStr = EncodeLatin1(cx, sourceTypeSource, sourceTypeBytes);
   if (!sourceTypeStr)
     return false;
 
   AutoString targetTypeSource;
-  JSAutoByteString targetTypeBytes;
+  JS::UniqueChars targetTypeBytes;
   BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
   if (!targetTypeSource)
       return false;
   const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource, targetTypeBytes);
   if (!targetTypeStr)
     return false;
 
   char sourceSizeStr[16];
@@ -1996,31 +1999,31 @@ SizeMismatchCastError(JSContext* cx,
                              targetTypeStr, sourceTypeStr,
                              targetSizeStr, sourceSizeStr);
   return false;
 }
 
 static bool
 UndefinedSizePointerError(JSContext* cx, const char* action, HandleObject obj)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   RootedValue val(cx, ObjectValue(*obj));
   const char* valStr = CTypesToSourceForError(cx, val, valBytes);
   if (!valStr)
     return false;
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                              CTYPESMSG_UNDEFINED_SIZE, action, valStr);
   return false;
 }
 
 static bool
 VariadicArgumentTypeError(JSContext* cx, uint32_t index, HandleValue actual)
 {
-  JSAutoByteString valBytes;
+  JS::UniqueChars valBytes;
   const char* valStr = CTypesToSourceForError(cx, actual, valBytes);
   if (!valStr)
     return false;
 
   char indexStr[16];
   SprintfLiteral(indexStr, "%u", index + 1);
 
   JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ctypes/Library.h"
 
 #include "prerror.h"
 #include "prlink.h"
 
 #include "ctypes/CTypes.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 
 using JS::AutoStableStringChars;
 
 namespace js {
 namespace ctypes {
 
 /*******************************************************************************
@@ -164,23 +164,23 @@ Library::Create(JSContext* cx, HandleVal
 #define MAX_ERROR_LEN 1024
     char error[MAX_ERROR_LEN] = "Cannot get error from NSPR.";
     uint32_t errorLen = PR_GetErrorTextLength();
     if (errorLen && errorLen < MAX_ERROR_LEN)
       PR_GetErrorText(error);
 #undef MAX_ERROR_LEN
 
     if (JS::StringIsASCII(error)) {
-      JSAutoByteString pathCharsUTF8;
-      if (pathCharsUTF8.encodeUtf8(cx, pathStr))
-        JS_ReportErrorUTF8(cx, "couldn't open library %s: %s", pathCharsUTF8.ptr(), error);
+      JS::UniqueChars pathCharsUTF8 = JS_EncodeStringToUTF8(cx, pathStr);
+      if (pathCharsUTF8)
+        JS_ReportErrorUTF8(cx, "couldn't open library %s: %s", pathCharsUTF8.get(), error);
     } else {
-      JSAutoByteString pathCharsLatin1;
-      if (pathCharsLatin1.encodeLatin1(cx, pathStr))
-        JS_ReportErrorLatin1(cx, "couldn't open library %s: %s", pathCharsLatin1.ptr(), error);
+      JS::UniqueChars pathCharsLatin1 = JS_EncodeString(cx, pathStr);
+      if (pathCharsLatin1)
+        JS_ReportErrorLatin1(cx, "couldn't open library %s: %s", pathCharsLatin1.get(), error);
     }
     return nullptr;
   }
 
   // stash the library
   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(library));
 
   return libraryObj;
--- a/js/src/frontend/EmitterScope.cpp
+++ b/js/src/frontend/EmitterScope.cpp
@@ -3,17 +3,16 @@
  * 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 "frontend/EmitterScope.h"
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TDZCheckCache.h"
-#include "js/AutoByteString.h"
 
 #include "vm/GlobalObject.h"
 
 using namespace js;
 using namespace js::frontend;
 
 using mozilla::DebugOnly;
 using mozilla::Maybe;
@@ -395,23 +394,23 @@ EmitterScope::deadZoneFrameSlotRange(Byt
 void
 EmitterScope::dump(BytecodeEmitter* bce)
 {
     fprintf(stdout, "EmitterScope [%s] %p\n", ScopeKindString(scope(bce)->kind()), this);
 
     for (NameLocationMap::Range r = nameCache_->all(); !r.empty(); r.popFront()) {
         const NameLocation& l = r.front().value();
 
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!AtomToPrintableString(bce->cx, r.front().key(), &bytes))
             return;
         if (l.kind() != NameLocation::Kind::Dynamic)
-            fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()), bytes.ptr());
+            fprintf(stdout, "  %s %s ", BindingKindString(l.bindingKind()), bytes.get());
         else
-            fprintf(stdout, "  %s ", bytes.ptr());
+            fprintf(stdout, "  %s ", bytes.get());
 
         switch (l.kind()) {
           case NameLocation::Kind::Dynamic:
             fprintf(stdout, "dynamic\n");
             break;
           case NameLocation::Kind::Global:
             fprintf(stdout, "global\n");
             break;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -32,17 +32,16 @@
 #include "jstypes.h"
 
 #include "builtin/ModuleObject.h"
 #include "builtin/SelfHostingDefines.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FoldConstants.h"
 #include "frontend/TokenStream.h"
 #include "irregexp/RegExpParser.h"
-#include "js/AutoByteString.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/RegExpObject.h"
 #include "vm/StringType.h"
 #include "wasm/AsmJS.h"
@@ -166,23 +165,23 @@ void
 ParseContext::Scope::dump(ParseContext* pc)
 {
     JSContext* cx = pc->sc()->context;
 
     fprintf(stdout, "ParseScope %p", this);
 
     fprintf(stdout, "\n  decls:\n");
     for (DeclaredNameMap::Range r = declared_->all(); !r.empty(); r.popFront()) {
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!AtomToPrintableString(cx, r.front().key(), &bytes))
             return;
         DeclaredNameInfo& info = r.front().value().wrapped;
         fprintf(stdout, "    %s %s%s\n",
                 DeclarationKindString(info.kind()),
-                bytes.ptr(),
+                bytes.get(),
                 info.closedOver() ? " (closed over)" : "");
     }
 
     fprintf(stdout, "\n");
 }
 
 bool
 ParseContext::Scope::addPossibleAnnexBFunctionBox(ParseContext* pc, FunctionBox* funbox)
@@ -1222,22 +1221,22 @@ GeneralParser<ParseHandler, CharT>::repo
 }
 
 template <class ParseHandler, typename CharT>
 void
 GeneralParser<ParseHandler, CharT>::reportRedeclaration(HandlePropertyName name,
                                                         DeclarationKind prevKind,
                                                         TokenPos pos, uint32_t prevPos)
 {
-    JSAutoByteString bytes;
+    UniqueChars bytes;
     if (!AtomToPrintableString(context, name, &bytes))
         return;
 
     if (prevPos == DeclaredNameInfo::npos) {
-        errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.ptr());
+        errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.get());
         return;
     }
 
     auto notes = MakeUnique<JSErrorNotes>();
     if (!notes) {
         ReportOutOfMemory(pc->sc()->context);
         return;
     }
@@ -1256,17 +1255,17 @@ GeneralParser<ParseHandler, CharT>::repo
                              GetErrorMessage, nullptr,
                              JSMSG_REDECLARED_PREV,
                              lineNumber, columnNumber))
     {
         return;
     }
 
     errorWithNotesAt(std::move(notes), pos.begin, JSMSG_REDECLARED_VAR,
-                     DeclarationKindString(prevKind), bytes.ptr());
+                     DeclarationKindString(prevKind), bytes.get());
 }
 
 // notePositionalFormalParameter is called for both the arguments of a regular
 // function definition and the arguments specified by the Function
 // constructor.
 //
 // The 'disallowDuplicateParams' bool indicates whether the use of another
 // feature (destructuring or default arguments) disables duplicate arguments.
@@ -1286,20 +1285,20 @@ GeneralParser<ParseHandler, CharT>::note
             return false;
         }
 
         // Strict-mode disallows duplicate args. We may not know whether we are
         // in strict mode or not (since the function body hasn't been parsed).
         // In such cases, report will queue up the potential error and return
         // 'true'.
         if (pc->sc()->needStrictChecks()) {
-            JSAutoByteString bytes;
+            UniqueChars bytes;
             if (!AtomToPrintableString(context, name, &bytes))
                 return false;
-            if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
+            if (!strictModeError(JSMSG_DUPLICATE_FORMAL, bytes.get()))
                 return false;
         }
 
         *duplicatedParam = true;
     } else {
         DeclarationKind kind = DeclarationKind::PositionalFormalParameter;
         if (!pc->functionScope().addDeclaredName(pc, p, name, kind, beginPos))
             return false;
@@ -2421,21 +2420,21 @@ Parser<FullParseHandler, CharT>::moduleB
 
     // Check exported local bindings exist and mark them as closed over.
     for (auto entry : modulesc->builder.localExportEntries()) {
         JSAtom* name = entry->localName();
         MOZ_ASSERT(name);
 
         DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
         if (!p) {
-            JSAutoByteString str;
+            UniqueChars str;
             if (!AtomToPrintableString(context, name, &str))
                 return null();
 
-            errorAt(TokenStream::NoOffset, JSMSG_MISSING_EXPORT, str.ptr());
+            errorAt(TokenStream::NoOffset, JSMSG_MISSING_EXPORT, str.get());
             return null();
         }
 
         p->value()->setClosedOver();
     }
 
     if (!FoldConstants(context, &pn, this))
         return null();
@@ -5459,21 +5458,21 @@ GeneralParser<ParseHandler, CharT>::impo
 
 template<typename CharT>
 bool
 Parser<FullParseHandler, CharT>::checkExportedName(JSAtom* exportName)
 {
     if (!pc->sc()->asModuleContext()->builder.hasExportedName(exportName))
         return true;
 
-    JSAutoByteString str;
+    UniqueChars str;
     if (!AtomToPrintableString(context, exportName, &str))
         return false;
 
-    error(JSMSG_DUPLICATE_EXPORT_NAME, str.ptr());
+    error(JSMSG_DUPLICATE_EXPORT_NAME, str.get());
     return false;
 }
 
 template<typename CharT>
 inline bool
 Parser<SyntaxParseHandler, CharT>::checkExportedName(JSAtom* exportName)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -12,17 +12,17 @@
 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "gc/GC.h"
 #include "js/AllocPolicy.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Vector.h"
 #include "vm/JSContext.h"
 
 /* Note: Aborts on OOM. */
 class JSAPITestString {
     js::Vector<char, 0, js::SystemAllocPolicy> chars;
 
   public:
@@ -100,19 +100,18 @@ class JSAPITest
 
 #define EVAL(s, vp) do { if (!evaluate(s, __FILE__, __LINE__, vp)) return false; } while (false)
 
     bool evaluate(const char* bytes, const char* filename, int lineno, JS::MutableHandleValue vp);
 
     JSAPITestString jsvalToSource(JS::HandleValue v) {
         JSString* str = JS_ValueToSource(cx, v);
         if (str) {
-            JSAutoByteString bytes(cx, str);
-            if (!!bytes)
-                return JSAPITestString(bytes.ptr());
+            if (JS::UniqueChars bytes = JS_EncodeString(cx, str))
+                return JSAPITestString(bytes.get());
         }
         JS_ClearPendingException(cx);
         return JSAPITestString("<<error converting value to string>>");
     }
 
     JSAPITestString toSource(long v) {
         char buf[40];
         sprintf(buf, "%ld", v);
@@ -228,19 +227,18 @@ class JSAPITest
 
         if (JS_IsExceptionPending(cx)) {
             js::gc::AutoSuppressGC gcoff(cx);
             JS::RootedValue v(cx);
             JS_GetPendingException(cx, &v);
             JS_ClearPendingException(cx);
             JSString* s = JS::ToString(cx, v);
             if (s) {
-                JSAutoByteString bytes(cx, s);
-                if (!!bytes)
-                    message += bytes.ptr();
+                if (JS::UniqueChars bytes = JS_EncodeString(cx, s))
+                    message += bytes.get();
             }
         }
 
         fprintf(stderr, "%.*s\n", int(message.length()), message.begin());
 
         if (msgs.length() != 0)
             msgs += " | ";
         msgs += message;
@@ -268,21 +266,20 @@ class JSAPITest
     print(JSContext* cx, unsigned argc, JS::Value* vp)
     {
         JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
         for (unsigned i = 0; i < args.length(); i++) {
             JSString* str = JS::ToString(cx, args[i]);
             if (!str)
                 return false;
-            char* bytes = JS_EncodeString(cx, str);
+            JS::UniqueChars bytes = JS_EncodeString(cx, str);
             if (!bytes)
                 return false;
-            printf("%s%s", i ? " " : "", bytes);
-            JS_free(cx, bytes);
+            printf("%s%s", i ? " " : "", bytes.get());
         }
 
         putchar('\n');
         fflush(stdout);
         args.rval().setUndefined();
         return true;
     }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -50,17 +50,16 @@
 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
 #include "gc/FreeOp.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "gc/PublicIterators.h"
 #include "gc/WeakMap.h"
 #include "jit/JitCommon.h"
 #include "jit/JitSpewer.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/Conversions.h"
 #include "js/Date.h"
 #include "js/Initialization.h"
 #include "js/JSON.h"
 #include "js/LocaleSensitive.h"
@@ -176,38 +175,38 @@ JS::ObjectOpResult::reportStrictErrorOrW
     }
 
     if (ErrorTakesArguments(code_)) {
         RootedValue idv(cx, IdToValue(id));
         RootedString str(cx, ValueToSource(cx, idv));
         if (!str)
             return false;
 
-        JSAutoByteString propName;
-        if (!propName.encodeUtf8(cx, str))
+        UniqueChars propName = JS_EncodeStringToUTF8(cx, str);
+        if (!propName)
             return false;
 
         if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) {
             // We know that the original receiver was a primitive, so unbox it.
             RootedValue val(cx, ObjectValue(*obj));
             if (!obj->is<ProxyObject>()) {
                 if (!Unbox(cx, obj, &val))
                     return false;
             }
             return ReportValueErrorFlags(cx, flags, code_, JSDVG_IGNORE_STACK, val,
-                                         nullptr, propName.ptr(), nullptr);
+                                         nullptr, propName.get(), nullptr);
         }
 
         if (ErrorTakesObjectArgument(code_)) {
             return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr, code_,
-                                                    obj->getClass()->name, propName.ptr());
+                                                    obj->getClass()->name, propName.get());
         }
 
         return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr, code_,
-                                                propName.ptr());
+                                                propName.get());
     }
     return JS_ReportErrorFlagsAndNumberASCII(cx, flags, GetErrorMessage, nullptr, code_);
 }
 
 JS_PUBLIC_API(bool)
 JS::ObjectOpResult::reportStrictErrorOrWarning(JSContext* cx, HandleObject obj, bool strict)
 {
     MOZ_ASSERT(code_ != Uninitialized);
@@ -1644,17 +1643,17 @@ JS::GetFirstArgumentAsTypeHint(JSContext
 
     if (!EqualStrings(cx, str, cx->names().number, &match))
         return false;
     if (match) {
         *result = JSTYPE_NUMBER;
         return true;
     }
 
-    JSAutoByteString bytes;
+    UniqueChars bytes;
     const char* source = ValueToSourceForError(cx, args.get(0), bytes);
     if (!source) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                                "Symbol.toPrimitive",
@@ -5061,30 +5060,28 @@ JS::GetPromiseResolutionSite(JS::HandleO
 }
 
 #ifdef DEBUG
 JS_PUBLIC_API(void)
 JS::DumpPromiseAllocationSite(JSContext* cx, JS::HandleObject promise)
 {
     RootedObject stack(cx, promise->as<PromiseObject>().allocationSite());
     JSPrincipals* principals = cx->realm()->principals();
-    UniqueChars stackStr(
-        reinterpret_cast<char*>(BuildUTF8StackString(cx, principals, stack).get()));
-    if (stackStr.get())
+    UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
+    if (stackStr)
         fputs(stackStr.get(), stderr);
 }
 
 JS_PUBLIC_API(void)
 JS::DumpPromiseResolutionSite(JSContext* cx, JS::HandleObject promise)
 {
     RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite());
     JSPrincipals* principals = cx->realm()->principals();
-    UniqueChars stackStr(
-        reinterpret_cast<char*>(BuildUTF8StackString(cx, principals, stack).get()));
-    if (stackStr.get())
+    UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack);
+    if (stackStr)
         fputs(stackStr.get(), stderr);
 }
 #endif
 
 JS_PUBLIC_API(JSObject*)
 JS::CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue)
 {
     AssertHeapIsIdle();
@@ -6050,32 +6047,32 @@ JS_DecodeBytes(JSContext* cx, const char
         return false;
     }
 
     CopyAndInflateChars(dst, src, srclen);
     *dstlenp = srclen;
     return true;
 }
 
-JS_PUBLIC_API(char*)
+JS_PUBLIC_API(JS::UniqueChars)
 JS_EncodeString(JSContext* cx, JSString* str)
 {
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
 
-    return js::EncodeLatin1(cx, str).release();
-}
-
-JS_PUBLIC_API(char*)
+    return js::EncodeLatin1(cx, str);
+}
+
+JS_PUBLIC_API(JS::UniqueChars)
 JS_EncodeStringToUTF8(JSContext* cx, HandleString str)
 {
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
 
-    return StringToNewUTF8CharsZ(cx, *str).release();
+    return StringToNewUTF8CharsZ(cx, *str);
 }
 
 JS_PUBLIC_API(size_t)
 JS_GetStringEncodingLength(JSContext* cx, JSString* str)
 {
     AssertHeapIsIdle();
     CHECK_THREAD(cx);
 
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -18,17 +18,16 @@
 
 #include "jsapi.h"
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "gc/FreeOp.h"
 #include "gc/Marking.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 #include "js/UniquePtr.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "vm/ErrorObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
@@ -879,17 +878,17 @@ ErrorReport::init(JSContext* cx, HandleV
             str = name;
         } else if (msg) {
             str = msg;
         }
 
         if (JS_GetProperty(cx, exnObject, filename_str, &val)) {
             RootedString tmp(cx, ToString<CanGC>(cx, val));
             if (tmp)
-                filename.encodeUtf8(cx, tmp);
+                filename = JS_EncodeStringToUTF8(cx, tmp);
             else
                 cx->clearPendingException();
         } else {
             cx->clearPendingException();
         }
 
         uint32_t lineno;
         if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &val) ||
@@ -904,17 +903,17 @@ ErrorReport::init(JSContext* cx, HandleV
             !ToUint32(cx, val, &column))
         {
             cx->clearPendingException();
             column = 0;
         }
 
         reportp = &ownedReport;
         new (reportp) JSErrorReport();
-        ownedReport.filename = filename.ptr();
+        ownedReport.filename = filename.get();
         ownedReport.lineno = lineno;
         ownedReport.exnType = JSEXN_INTERNALERR;
         ownedReport.column = column;
         if (str) {
             // Note that using |str| for |message_| here is kind of wrong,
             // because |str| is supposed to be of the format
             // |ErrorName: ErrorMessage|, and |message_| is supposed to
             // correspond to |ErrorMessage|. But this is what we've
@@ -930,18 +929,20 @@ ErrorReport::init(JSContext* cx, HandleV
             } else {
                 cx->clearPendingException();
                 str = nullptr;
             }
         }
     }
 
     const char* utf8Message = nullptr;
-    if (str)
-        utf8Message = toStringResultBytesStorage.encodeUtf8(cx, str);
+    if (str) {
+        toStringResultBytesStorage = JS_EncodeStringToUTF8(cx, str);
+        utf8Message = toStringResultBytesStorage.get();
+    }
     if (!utf8Message)
         utf8Message = "unknown (can't convert to string)";
 
     if (!reportp) {
         // This is basically an inlined version of
         //
         //   JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
         //                            JSMSG_UNCAUGHT_EXCEPTION, utf8Message);
@@ -1049,17 +1050,17 @@ JS::CreateError(JSContext* cx, JSExnType
     if (!obj)
         return false;
 
     rval.setObject(*obj);
     return true;
 }
 
 const char*
-js::ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes)
+js::ValueToSourceForError(JSContext* cx, HandleValue val, UniqueChars& bytes)
 {
     if (val.isUndefined())
         return "undefined";
 
     if (val.isNull())
         return "null";
 
     AutoClearPendingException acpe(cx);
@@ -1088,24 +1089,26 @@ js::ValueToSourceForError(JSContext* cx,
     } else if (val.isNumber()) {
         if (!sb.append("the number "))
             return "<<error converting value to string>>";
     } else if (val.isString()) {
         if (!sb.append("the string "))
             return "<<error converting value to string>>";
     } else {
         MOZ_ASSERT(val.isBoolean() || val.isSymbol());
-        return bytes.encodeLatin1(cx, str);
+        bytes = JS_EncodeString(cx, str);
+        return bytes.get();
     }
     if (!sb.append(str))
         return "<<error converting value to string>>";
     str = sb.finishString();
     if (!str)
         return "<<error converting value to string>>";
-    return bytes.encodeLatin1(cx, str);
+    bytes = JS_EncodeString(cx, str);
+    return bytes.get();
 }
 
 bool
 js::GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
 {
     FixedInvokeArgs<1> args(cx);
     args[0].set(Int32Value(errorNumber));
     return CallSelfHostedFunction(cx, cx->names().GetInternalError, NullHandleValue, args, error);
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -12,18 +12,16 @@
 #define jsexn_h
 
 #include "jsapi.h"
 #include "NamespaceImports.h"
 
 #include "js/UniquePtr.h"
 #include "vm/JSContext.h"
 
-class JSAutoByteString;
-
 namespace js {
 class ErrorObject;
 
 UniquePtr<JSErrorNotes::Note>
 CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note);
 
 UniquePtr<JSErrorReport>
 CopyErrorReport(JSContext* cx, JSErrorReport* report);
@@ -129,17 +127,17 @@ class AutoAssertNoPendingException
     { }
 
     ~AutoAssertNoPendingException() {
         MOZ_ASSERT(!JS_IsExceptionPending(cx));
     }
 };
 
 extern const char*
-ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes);
+ValueToSourceForError(JSContext* cx, HandleValue val, JS::UniqueChars& bytes);
 
 bool
 GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
 bool
 GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
 
 } // namespace js
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -15,17 +15,17 @@
 #ifdef ENABLE_BIGINT
 #include "builtin/BigInt.h"
 #endif
 #include "builtin/Promise.h"
 #include "builtin/TestingFunctions.h"
 #include "gc/GCInternals.h"
 #include "gc/PublicIterators.h"
 #include "gc/WeakMap.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Printf.h"
 #include "js/Proxy.h"
 #include "js/Wrapper.h"
 #include "proxy/DeadObjectProxy.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/Realm.h"
@@ -803,17 +803,17 @@ JS_FRIEND_API(bool)
 js::DumpScript(JSContext* cx, JSScript* scriptArg)
 {
     return DumpScript(cx, scriptArg, stdout);
 }
 
 #endif
 
 static const char*
-FormatValue(JSContext* cx, const Value& vArg, JSAutoByteString& bytes)
+FormatValue(JSContext* cx, const Value& vArg, UniqueChars& bytes)
 {
     RootedValue v(cx, vArg);
 
     if (v.isMagic(JS_OPTIMIZED_OUT))
         return "[unavailable]";
 
     /*
      * We could use Maybe<AutoRealm> here, but G++ can't quite follow
@@ -827,17 +827,18 @@ FormatValue(JSContext* cx, const Value& 
         AutoRealm ar(cx, &v.toObject());
         str = ToString<CanGC>(cx, v);
     } else {
         str = ToString<CanGC>(cx, v);
     }
 
     if (!str)
         return nullptr;
-    const char* buf = bytes.encodeLatin1(cx, str);
+    bytes = JS_EncodeString(cx, str);
+    const char* buf = bytes.get();
     if (!buf)
         return nullptr;
     const char* found = strstr(buf, "function ");
     if (found && (found - buf <= 2))
         return "[function]";
     return buf;
 }
 
@@ -887,18 +888,18 @@ FormatFrame(JSContext* cx, const FrameIt
     {
         if (!GetFunctionThis(cx, iter.abstractFramePtr(), &thisVal))
             return nullptr;
     }
 
     // print the frame number and function name
     JS::UniqueChars buf(std::move(inBuf));
     if (funname) {
-        JSAutoByteString funbytes;
-        char* str = funbytes.encodeLatin1(cx, funname);
+        UniqueChars funbytes = JS_EncodeString(cx, funname);
+        char* str = funbytes.get();
         if (!str)
             return nullptr;
         buf = sprintf_append(cx, std::move(buf), "%d %s(", num, str);
     } else if (fun) {
         buf = sprintf_append(cx, std::move(buf), "%d anonymous(", num);
     } else {
         buf = sprintf_append(cx, std::move(buf), "%d <TOP LEVEL>", num);
     }
@@ -920,31 +921,32 @@ FormatFrame(JSContext* cx, const FrameIt
                     arg = iter.argsObj().arg(i);
                 } else {
                     arg = iter.unaliasedActual(i, DONT_CHECK_ALIASING);
                 }
             } else {
                 arg = MagicValue(JS_OPTIMIZED_OUT);
             }
 
-            JSAutoByteString valueBytes;
+            UniqueChars valueBytes;
             const char* value = FormatValue(cx, arg, valueBytes);
             if (!value) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
 
-            JSAutoByteString nameBytes;
+            UniqueChars nameBytes;
             const char* name = nullptr;
 
             if (i < iter.numFormalArgs()) {
                 MOZ_ASSERT(fi.argumentSlot() == i);
                 if (!fi.isDestructured()) {
-                    name = nameBytes.encodeLatin1(cx, fi.name());
+                    nameBytes = JS_EncodeString(cx, fi.name());
+                    name = nameBytes.get();
                     if (!name)
                         return nullptr;
                 } else {
                     name = "(destructured parameter)";
                 }
                 fi++;
             }
 
@@ -980,25 +982,26 @@ FormatFrame(JSContext* cx, const FrameIt
 
 
     // Note: Right now we don't dump the local variables anymore, because
     // that is hard to support across all the JITs etc.
 
     // print the value of 'this'
     if (showLocals) {
         if (!thisVal.isUndefined()) {
-            JSAutoByteString thisValBytes;
+            UniqueChars thisValBytes;
             RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
             if (!thisValStr) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
             if (thisValStr) {
-                const char* str = thisValBytes.encodeLatin1(cx, thisValStr);
+                thisValBytes = JS_EncodeString(cx, thisValStr);
+                const char* str = thisValBytes.get();
                 if (!str)
                     return nullptr;
                 buf = sprintf_append(cx, std::move(buf), "    this = %s\n", str);
             } else {
                 buf = sprintf_append(cx, std::move(buf), "    <failed to get 'this' value>\n");
             }
             if (!buf)
                 return nullptr;
@@ -1027,25 +1030,25 @@ FormatFrame(JSContext* cx, const FrameIt
                 cx->clearPendingException();
                 buf = sprintf_append(cx, std::move(buf),
                                      "    <Failed to fetch property while inspecting stack frame>\n");
                 if (!buf)
                     return nullptr;
                 continue;
             }
 
-            JSAutoByteString nameBytes;
+            UniqueChars nameBytes;
             const char* name = FormatValue(cx, key, nameBytes);
             if (!name) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
 
-            JSAutoByteString valueBytes;
+            UniqueChars valueBytes;
             const char* value = FormatValue(cx, v, valueBytes);
             if (!value) {
                 if (cx->isThrowingOutOfMemory())
                     return nullptr;
                 cx->clearPendingException();
             }
 
             if (name && value) {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -10,17 +10,16 @@
 #include "mozilla/Atomics.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/UniquePtr.h"
 
 #include "jspubtd.h"
 
-#include "js/AutoByteString.h"
 #include "js/CallArgs.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/CharacterEncoding.h"
 #include "js/Class.h"
 #include "js/ErrorReport.h"
 #include "js/HeapAPI.h"
 #include "js/StableStringChars.h"
 #include "js/TypeDecls.h"
@@ -1459,23 +1458,23 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(Err
 
     // And keep its chars alive too.
     JS::AutoStableStringChars strChars;
 
     // And we need to root our exception value.
     JS::RootedObject exnObject;
 
     // And for our filename.
-    JSAutoByteString filename;
+    JS::UniqueChars filename;
 
     // We may have a result of error.toString().
     // FIXME: We should not call error.toString(), since it could have side
     //        effect (see bug 633623).
     JS::ConstUTF8CharsZ toStringResult_;
-    JSAutoByteString toStringResultBytesStorage;
+    JS::UniqueChars toStringResultBytesStorage;
 };
 
 /* Implemented in vm/StructuredClone.cpp. */
 extern JS_FRIEND_API(uint64_t)
 GetSCOffset(JSStructuredCloneWriter* writer);
 
 namespace Scalar {
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -22,16 +22,17 @@
 #endif
 #include <math.h>
 #include <string.h>
 
 #include "jstypes.h"
 
 #include "builtin/String.h"
 #include "double-conversion/double-conversion.h"
+#include "js/CharacterEncoding.h"
 #include "js/Conversions.h"
 #if !EXPOSE_INTL_API
 #include "js/LocaleSensitive.h"
 #endif
 #include "util/DoubleToString.h"
 #include "util/StringBuffer.h"
 #ifdef ENABLE_BIGINT
 #include "vm/BigIntType.h"
@@ -791,20 +792,20 @@ num_toLocaleString_impl(JSContext* cx, c
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     /*
      * Create the string, move back to bytes to make string twiddling
      * a bit easier and so we can insert platform charset seperators.
      */
-    JSAutoByteString numBytes(cx, str);
+    UniqueChars numBytes = JS_EncodeString(cx, str);
     if (!numBytes)
         return false;
-    const char* num = numBytes.ptr();
+    const char* num = numBytes.get();
     if (!num)
         return false;
 
     /*
      * Find the first non-integer value, whether it be a letter as in
      * 'Infinity', a decimal point, or an 'e' from exponential notation.
      */
     const char* nint = num;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -119,17 +119,16 @@ EXPORTS += [
     'jsfriendapi.h',
     'jspubtd.h',
     'jstypes.h',
     'perf/jsperf.h',
 ]
 
 EXPORTS.js += [
     '../public/AllocPolicy.h',
-    '../public/AutoByteString.h',
     '../public/CallArgs.h',
     '../public/CallNonGenericMethod.h',
     '../public/CharacterEncoding.h',
     '../public/Class.h',
     '../public/CompilationAndEvaluation.h',
     '../public/CompileOptions.h',
     '../public/Conversions.h',
     '../public/Date.h',
--- a/js/src/proxy/ScriptedProxyHandler.cpp
+++ b/js/src/proxy/ScriptedProxyHandler.cpp
@@ -3,17 +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 "proxy/ScriptedProxyHandler.h"
 
 #include "jsapi.h"
 
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "vm/Interpreter.h" // For InstanceOfOperator
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 
 using JS::IsArrayAnswer;
@@ -174,21 +174,21 @@ GetProxyTrap(JSContext* cx, HandleObject
 
     if (func.isNull()) {
         func.setUndefined();
         return true;
     }
 
     // Step 4.
     if (!IsCallable(func)) {
-        JSAutoByteString bytes(cx, name);
+        UniqueChars bytes = JS_EncodeString(cx, name);
         if (!bytes)
             return false;
 
-        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_BAD_TRAP, bytes.ptr());
+        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_BAD_TRAP, bytes.get());
         return false;
     }
 
     return true;
 }
 
 // ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.1 Proxy.[[GetPrototypeOf]].
 bool
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -20,17 +20,17 @@
 #endif
 
 #include "jsapi.h"
 // For JSFunctionSpecWithHelp
 #include "jsfriendapi.h"
 
 #include "builtin/String.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Conversions.h"
 #include "js/Wrapper.h"
 #include "shell/jsshell.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "util/Windows.h"
 #include "vm/JSObject.h"
 #include "vm/TypedArrayObject.h"
@@ -53,19 +53,19 @@ namespace shell {
 
 #ifdef XP_WIN
 const char PathSeparator = '\\';
 #else
 const char PathSeparator = '/';
 #endif
 
 static bool
-IsAbsolutePath(const JSAutoByteString& filename)
+IsAbsolutePath(const UniqueChars& filename)
 {
-    const char* pathname = filename.ptr();
+    const char* pathname = filename.get();
 
     if (pathname[0] == PathSeparator)
         return true;
 
 #ifdef XP_WIN
     // On Windows there are various forms of absolute paths (see
     // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
     // for details):
@@ -101,17 +101,17 @@ ResolvePath(JSContext* cx, HandleString 
     if (!filenameStr) {
 #ifdef XP_WIN
         return JS_NewStringCopyZ(cx, "nul");
 #else
         return JS_NewStringCopyZ(cx, "/dev/null");
 #endif
     }
 
-    JSAutoByteString filename(cx, filenameStr);
+    UniqueChars filename = JS_EncodeString(cx, filenameStr);
     if (!filename)
         return nullptr;
 
     if (IsAbsolutePath(filename))
         return filenameStr;
 
     JS::AutoFilename scriptFilename;
     if (resolveMode == ScriptRelative) {
@@ -143,89 +143,89 @@ ResolvePath(JSContext* cx, HandleString 
     } else {
         const char* cwd = getcwd(buffer, PATH_MAX);
         if (!cwd)
             return nullptr;
     }
 
     size_t len = strlen(buffer);
     buffer[len] = '/';
-    strncpy(buffer + len + 1, filename.ptr(), sizeof(buffer) - (len+1));
+    strncpy(buffer + len + 1, filename.get(), sizeof(buffer) - (len+1));
     if (buffer[PATH_MAX] != '\0')
         return nullptr;
 
     return JS_NewStringCopyZ(cx, buffer);
 }
 
 JSObject*
 FileAsTypedArray(JSContext* cx, JS::HandleString pathnameStr)
 {
-    JSAutoByteString pathname(cx, pathnameStr);
+    UniqueChars pathname = JS_EncodeString(cx, pathnameStr);
     if (!pathname)
         return nullptr;
 
-    FILE* file = fopen(pathname.ptr(), "rb");
+    FILE* file = fopen(pathname.get(), "rb");
     if (!file) {
         /*
          * Use Latin1 variant here because the encoding of the return value of
          * strerror function can be non-UTF-8.
          */
-        JS_ReportErrorLatin1(cx, "can't open %s: %s", pathname.ptr(), strerror(errno));
+        JS_ReportErrorLatin1(cx, "can't open %s: %s", pathname.get(), strerror(errno));
         return nullptr;
     }
     AutoCloseFile autoClose(file);
 
     RootedObject obj(cx);
     if (fseek(file, 0, SEEK_END) != 0) {
-        pathname.clear();
-        if (!pathname.encodeUtf8(cx, pathnameStr))
+        pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+        if (!pathname)
             return nullptr;
-        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.ptr());
+        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.get());
     } else {
         size_t len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
-            pathname.clear();
-            if (!pathname.encodeUtf8(cx, pathnameStr))
+            pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+            if (!pathname)
                 return nullptr;
-            JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
+            JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.get());
         } else {
             obj = JS_NewUint8Array(cx, len);
             if (!obj)
                 return nullptr;
             js::TypedArrayObject& ta = obj->as<js::TypedArrayObject>();
             if (ta.isSharedMemory()) {
                 // Must opt in to use shared memory.  For now, don't.
                 //
                 // (It is incorrect to read into the buffer without
                 // synchronization since that can create a race.  A
                 // lock here won't fix it - both sides must
                 // participate.  So what one must do is to create a
                 // temporary buffer, read into that, and use a
                 // race-safe primitive to copy memory into the
                 // buffer.)
-                pathname.clear();
-                if (!pathname.encodeUtf8(cx, pathnameStr))
+                pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+                if (!pathname)
                     return nullptr;
-                JS_ReportErrorUTF8(cx, "can't read %s: shared memory buffer", pathname.ptr());
+                JS_ReportErrorUTF8(cx, "can't read %s: shared memory buffer", pathname.get());
                 return nullptr;
             }
             char* buf = static_cast<char*>(ta.viewDataUnshared());
             size_t cc = fread(buf, 1, len, file);
             if (cc != len) {
                 if (ptrdiff_t(cc) < 0) {
                     /*
                      * Use Latin1 variant here because the encoding of the return
                      * value of strerror function can be non-UTF-8.
                      */
-                    JS_ReportErrorLatin1(cx, "can't read %s: %s", pathname.ptr(), strerror(errno));
+                    JS_ReportErrorLatin1(cx, "can't read %s: %s", pathname.get(), strerror(errno));
                 } else {
-                    pathname.clear();
-                    if (!pathname.encodeUtf8(cx, pathnameStr))
+                    pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+                    if (!pathname)
                         return nullptr;
-                    JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.ptr());
+                    JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.get());
                 }
                 obj = nullptr;
             }
         }
     }
     return obj;
 }
 
@@ -314,51 +314,51 @@ osfile_writeTypedArrayToFile(JSContext* 
         return false;
     }
 
     RootedString givenPath(cx, args[0].toString());
     RootedString str(cx, ResolvePath(cx, givenPath, RootRelative));
     if (!str)
         return false;
 
-    JSAutoByteString filename(cx, str);
+    UniqueChars filename = JS_EncodeString(cx, str);
     if (!filename)
         return false;
 
-    FILE* file = fopen(filename.ptr(), "wb");
+    FILE* file = fopen(filename.get(), "wb");
     if (!file) {
         /*
          * Use Latin1 variant here because the encoding of the return value of
          * strerror function can be non-UTF-8.
          */
-        JS_ReportErrorLatin1(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
+        JS_ReportErrorLatin1(cx, "can't open %s: %s", filename.get(), strerror(errno));
         return false;
     }
     AutoCloseFile autoClose(file);
 
     TypedArrayObject* obj = &args[1].toObject().as<TypedArrayObject>();
 
     if (obj->isSharedMemory()) {
         // Must opt in to use shared memory.  For now, don't.
         //
         // See further comments in FileAsTypedArray, above.
-        filename.clear();
-        if (!filename.encodeUtf8(cx, str))
+        filename = JS_EncodeStringToUTF8(cx, str);
+        if (!filename)
             return false;
-        JS_ReportErrorUTF8(cx, "can't write %s: shared memory buffer", filename.ptr());
+        JS_ReportErrorUTF8(cx, "can't write %s: shared memory buffer", filename.get());
         return false;
     }
     void* buf = obj->viewDataUnshared();
     if (fwrite(buf, obj->bytesPerElement(), obj->length(), file) != obj->length() ||
         !autoClose.release())
     {
-        filename.clear();
-        if (!filename.encodeUtf8(cx, str))
+        filename = JS_EncodeStringToUTF8(cx, str);
+        if (!filename)
             return false;
-        JS_ReportErrorUTF8(cx, "can't write %s", filename.ptr());
+        JS_ReportErrorUTF8(cx, "can't write %s", filename.get());
         return false;
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 /* static */ RCFile*
@@ -467,26 +467,26 @@ const js::Class FileObject::class_ = {
 };
 
 static FileObject*
 redirect(JSContext* cx, HandleString relFilename, RCFile** globalFile)
 {
     RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
     if (!filename)
         return nullptr;
-    JSAutoByteString filenameABS(cx, filename);
+    UniqueChars filenameABS = JS_EncodeString(cx, filename);
     if (!filenameABS)
         return nullptr;
-    RCFile* file = RCFile::create(cx, filenameABS.ptr(), "wb");
+    RCFile* file = RCFile::create(cx, filenameABS.get(), "wb");
     if (!file) {
         /*
          * Use Latin1 variant here because the encoding of the return value of
          * strerror function can be non-UTF-8.
          */
-        JS_ReportErrorLatin1(cx, "cannot redirect to %s: %s", filenameABS.ptr(), strerror(errno));
+        JS_ReportErrorLatin1(cx, "cannot redirect to %s: %s", filenameABS.get(), strerror(errno));
         return nullptr;
     }
 
     // Grant the global gOutFile ownership of the new file, release ownership
     // of its old file, and return a FileObject owning the old file.
     file->acquire(); // Global owner of new file
 
     FileObject* fileObj = FileObject::create(cx, *globalFile); // Newly created owner of old file
@@ -631,17 +631,17 @@ ospath_isAbsolute(JSContext* cx, unsigne
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 1 || !args[0].isString()) {
         JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
                                   "isAbsolute");
         return false;
     }
 
-    JSAutoByteString path(cx, args[0].toString());
+    UniqueChars path = JS_EncodeString(cx, args[0].toString());
     if (!path)
         return false;
 
     args.rval().setBoolean(IsAbsolutePath(path));
     return true;
 }
 
 static bool
@@ -660,17 +660,17 @@ ospath_join(JSContext* cx, unsigned argc
     StringBuffer buffer(cx);
 
     for (unsigned i = 0; i < args.length(); i++) {
         if (!args[i].isString()) {
             JS_ReportErrorASCII(cx, "join expects string arguments only");
             return false;
         }
 
-        JSAutoByteString path(cx, args[i].toString());
+        UniqueChars path = JS_EncodeString(cx, args[i].toString());
         if (!path)
             return false;
 
         if (IsAbsolutePath(path)) {
             MOZ_ALWAYS_TRUE(buffer.resize(0));
         } else if (i != 0) {
             if (!buffer.append(PathSeparator))
                 return false;
@@ -706,21 +706,21 @@ os_getenv(JSContext* cx, unsigned argc, 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportErrorASCII(cx, "os.getenv requires 1 argument");
         return false;
     }
     RootedString key(cx, ToString(cx, args[0]));
     if (!key)
         return false;
-    JSAutoByteString keyBytes;
-    if (!keyBytes.encodeUtf8(cx, key))
+    UniqueChars keyBytes = JS_EncodeStringToUTF8(cx, key);
+    if (!keyBytes)
         return false;
 
-    if (const char* valueBytes = getenv(keyBytes.ptr())) {
+    if (const char* valueBytes = getenv(keyBytes.get())) {
         RootedString value(cx, JS_NewStringCopyZ(cx, valueBytes));
         if (!value)
             return false;
         args.rval().setString(value);
     } else {
         args.rval().setUndefined();
     }
     return true;
@@ -790,21 +790,21 @@ os_system(JSContext* cx, unsigned argc, 
         JS_ReportErrorASCII(cx, "os.system requires 1 argument");
         return false;
     }
 
     JSString* str = JS::ToString(cx, args[0]);
     if (!str)
         return false;
 
-    JSAutoByteString command(cx, str);
+    UniqueChars command = JS_EncodeString(cx, str);
     if (!command)
         return false;
 
-    int result = system(command.ptr());
+    int result = system(command.get());
     if (result == -1) {
         ReportSysError(cx, "system call failed");
         return false;
     }
 
     args.rval().setInt32(result);
     return true;
 }
@@ -819,17 +819,17 @@ os_spawn(JSContext* cx, unsigned argc, V
         JS_ReportErrorASCII(cx, "os.spawn requires 1 argument");
         return false;
     }
 
     JSString* str = JS::ToString(cx, args[0]);
     if (!str)
         return false;
 
-    JSAutoByteString command(cx, str);
+    UniqueChars command = JS_EncodeString(cx, str);
     if (!command)
         return false;
 
     int32_t childPid = fork();
     if (childPid == -1) {
         ReportSysError(cx, "fork failed");
         return false;
     }
@@ -837,17 +837,17 @@ os_spawn(JSContext* cx, unsigned argc, V
     if (childPid) {
         args.rval().setInt32(childPid);
         return true;
     }
 
     // We are in the child
 
     const char* cmd[] = {"sh", "-c", nullptr, nullptr};
-    cmd[2] = command.ptr();
+    cmd[2] = command.get();
 
     execvp("sh", (char * const*)cmd);
     exit(1);
 }
 
 static bool
 os_kill(JSContext* cx, unsigned argc, Value* vp)
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -72,17 +72,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/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/CompileOptions.h"
 #include "js/Debug.h"
 #include "js/GCVector.h"
 #include "js/Initialization.h"
 #include "js/JSON.h"
 #include "js/Printf.h"
 #include "js/SourceBufferHolder.h"
@@ -1048,46 +1048,51 @@ BoundToAsyncStack(JSContext* cx, unsigne
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedFunction function(cx, (&GetFunctionNativeReserved(&args.callee(), 0)
                                  .toObject().as<JSFunction>()));
     RootedObject options(cx, &GetFunctionNativeReserved(&args.callee(), 1).toObject());
 
     RootedSavedFrame stack(cx, nullptr);
-    JSAutoByteString cause;
     bool isExplicit;
 
     RootedValue v(cx);
 
     if (!JS_GetProperty(cx, options, "stack", &v))
         return false;
     if (!v.isObject() || !v.toObject().is<SavedFrame>()) {
         JS_ReportErrorASCII(cx, "The 'stack' property must be a SavedFrame object.");
         return false;
     }
     stack = &v.toObject().as<SavedFrame>();
 
     if (!JS_GetProperty(cx, options, "cause", &v))
         return false;
     RootedString causeString(cx, ToString(cx, v));
-    if (!causeString || !cause.encodeUtf8(cx, causeString)) {
+    if (!causeString) {
+        MOZ_ASSERT(cx->isExceptionPending());
+        return false;
+    }
+
+    UniqueChars cause = JS_EncodeStringToUTF8(cx, causeString);
+    if (!cause) {
         MOZ_ASSERT(cx->isExceptionPending());
         return false;
     }
 
     if (!JS_GetProperty(cx, options, "explicit", &v))
         return false;
     isExplicit = v.isUndefined() ? true : ToBoolean(v);
 
     auto kind = (isExplicit
                  ? JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::EXPLICIT
                  : JS::AutoSetAsyncStackForNewCalls::AsyncCallKind::IMPLICIT);
 
-    JS::AutoSetAsyncStackForNewCalls asasfnckthxbye(cx, stack, cause.ptr(), kind);
+    JS::AutoSetAsyncStackForNewCalls asasfnckthxbye(cx, stack, cause.get(), kind);
     return Call(cx, UndefinedHandleValue, function,
                 JS::HandleValueArray::empty(), args.rval());
 }
 
 static bool
 BindToAsyncStack(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1171,21 +1176,20 @@ EvalAndPrint(JSContext* cx, const char* 
 
     if (!result.isUndefined() && gOutFile->isOpen()) {
         // Print.
         RootedString str(cx);
         str = JS_ValueToSource(cx, result);
         if (!str)
             return false;
 
-        char* utf8chars = JS_EncodeStringToUTF8(cx, str);
+        UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, str);
         if (!utf8chars)
             return false;
-        fprintf(gOutFile->fp, "%s\n", utf8chars);
-        JS_free(cx, utf8chars);
+        fprintf(gOutFile->fp, "%s\n", utf8chars.get());
     }
     return true;
 }
 
 static MOZ_MUST_USE bool
 ReadEvalPrintLoop(JSContext* cx, FILE* in, bool compileOnly)
 {
     ShellContext* sc = GetShellContext(cx);
@@ -1355,17 +1359,17 @@ CreateMappedArrayBuffer(JSContext* cx, u
         return false;
     // It's a little bizarre to resolve relative to the script, but for testing
     // I need a file at a known location, and the only good way I know of to do
     // that right now is to include it in the repo alongside the test script.
     // Bug 944164 would introduce an alternative.
     JSString* filenameStr = ResolvePath(cx, rawFilenameStr, ScriptRelative);
     if (!filenameStr)
         return false;
-    JSAutoByteString filename(cx, filenameStr);
+    UniqueChars filename = JS_EncodeString(cx, filenameStr);
     if (!filename)
         return false;
 
     uint32_t offset = 0;
     if (args.length() >= 2) {
         if (!JS::ToUint32(cx, args[1], &offset))
             return false;
     }
@@ -1377,19 +1381,19 @@ CreateMappedArrayBuffer(JSContext* cx, u
             return false;
         sizeGiven = true;
         if (size == 0) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
             return false;
         }
     }
 
-    FILE* file = fopen(filename.ptr(), "rb");
+    FILE* file = fopen(filename.get(), "rb");
     if (!file) {
-        ReportCantOpenErrorUnknownEncoding(cx, filename.ptr());
+        ReportCantOpenErrorUnknownEncoding(cx, filename.get());
         return false;
     }
     AutoCloseFile autoClose(file);
 
     if (!sizeGiven) {
         struct stat st;
         if (fstat(fileno(file), &st) < 0) {
             JS_ReportErrorASCII(cx, "Unable to stat file");
@@ -1465,41 +1469,41 @@ Options(JSContext* cx, unsigned argc, Va
 
     JS::ContextOptions oldContextOptions = JS::ContextOptionsRef(cx);
     for (unsigned i = 0; i < args.length(); i++) {
         RootedString str(cx, JS::ToString(cx, args[i]));
         if (!str)
             return false;
         args[i].setString(str);
 
-        JSAutoByteString opt;
-        if (!opt.encodeUtf8(cx, str))
-            return false;
-
-        if (strcmp(opt.ptr(), "strict") == 0) {
+        UniqueChars opt = JS_EncodeStringToUTF8(cx, str);
+        if (!opt)
+            return false;
+
+        if (strcmp(opt.get(), "strict") == 0) {
             JS::ContextOptionsRef(cx).toggleExtraWarnings();
-        } else if (strcmp(opt.ptr(), "werror") == 0) {
+        } else if (strcmp(opt.get(), "werror") == 0) {
             // Disallow toggling werror when there are off-thread jobs, to avoid
             // confusing CompileError::throwError.
             ShellContext* sc = GetShellContext(cx);
             if (!sc->offThreadJobs.empty()) {
                 JS_ReportErrorASCII(cx, "can't toggle werror when there are off-thread jobs");
                 return false;
             }
             JS::ContextOptionsRef(cx).toggleWerror();
-        } else if (strcmp(opt.ptr(), "throw_on_asmjs_validation_failure") == 0) {
+        } else if (strcmp(opt.get(), "throw_on_asmjs_validation_failure") == 0) {
             JS::ContextOptionsRef(cx).toggleThrowOnAsmJSValidationFailure();
-        } else if (strcmp(opt.ptr(), "strict_mode") == 0) {
+        } else if (strcmp(opt.get(), "strict_mode") == 0) {
             JS::ContextOptionsRef(cx).toggleStrictMode();
         } else {
             JS_ReportErrorUTF8(cx,
                                "unknown option name '%s'."
                                " The valid names are strict,"
                                " werror, and strict_mode.",
-                               opt.ptr());
+                               opt.get());
             return false;
         }
     }
 
     UniqueChars names = DuplicateString("");
     bool found = false;
     if (names && oldContextOptions.extraWarnings()) {
         names = JS_sprintf_append(std::move(names), "%s%s", found ? "," : "", "strict");
@@ -1542,29 +1546,29 @@ LoadScript(JSContext* cx, unsigned argc,
                                       "load");
             return false;
         }
         str = ResolvePath(cx, str, scriptRelative ? ScriptRelative : RootRelative);
         if (!str) {
             JS_ReportErrorASCII(cx, "unable to resolve path");
             return false;
         }
-        JSAutoByteString filename(cx, str);
+        UniqueChars filename = JS_EncodeString(cx, str);
         if (!filename)
             return false;
         errno = 0;
         CompileOptions opts(cx);
         opts.setIntroductionType("js shell load")
             .setUTF8(true)
             .setIsRunOnce(true)
             .setNoScriptRval(true);
         RootedScript script(cx);
         RootedValue unused(cx);
-        if ((compileOnly && !Compile(cx, opts, filename.ptr(), &script)) ||
-            !Evaluate(cx, opts, filename.ptr(), &unused))
+        if ((compileOnly && !Compile(cx, opts, filename.get(), &script)) ||
+            !Evaluate(cx, opts, filename.get(), &unused))
         {
             return false;
         }
     }
 
     args.rval().setUndefined();
     return true;
 }
@@ -1581,17 +1585,17 @@ LoadScriptRelativeToScript(JSContext* cx
     return LoadScript(cx, argc, vp, true);
 }
 
 // Populate |options| with the options given by |opts|'s properties. If we
 // need to convert a filename to a C string, let fileNameBytes own the
 // bytes.
 static bool
 ParseCompileOptions(JSContext* cx, CompileOptions& options, HandleObject opts,
-                    JSAutoByteString& fileNameBytes)
+                    UniqueChars& fileNameBytes)
 {
     RootedValue v(cx);
     RootedString s(cx);
 
     if (!JS_GetProperty(cx, opts, "isRunOnce", &v))
         return false;
     if (!v.isUndefined())
         options.setIsRunOnce(ToBoolean(v));
@@ -1604,17 +1608,18 @@ ParseCompileOptions(JSContext* cx, Compi
     if (!JS_GetProperty(cx, opts, "fileName", &v))
         return false;
     if (v.isNull()) {
         options.setFile(nullptr);
     } else if (!v.isUndefined()) {
         s = ToString(cx, v);
         if (!s)
             return false;
-        char* fileName = fileNameBytes.encodeLatin1(cx, s);
+        fileNameBytes = JS_EncodeString(cx, s);
+        char* fileName = fileNameBytes.get();
         if (!fileName)
             return false;
         options.setFile(fileName);
     }
 
     if (!JS_GetProperty(cx, opts, "element", &v))
         return false;
     if (v.isObject())
@@ -1813,17 +1818,17 @@ Evaluate(JSContext* cx, unsigned argc, V
     }
 
     if (!code || (args.length() == 2 && args[1].isPrimitive())) {
         JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "evaluate");
         return false;
     }
 
     CompileOptions options(cx);
-    JSAutoByteString fileNameBytes;
+    UniqueChars fileNameBytes;
     RootedString displayURL(cx);
     RootedString sourceMapURL(cx);
     RootedObject global(cx, nullptr);
     bool catchTermination = false;
     bool loadBytecode = false;
     bool saveBytecode = false;
     bool saveIncrementalBytecode = false;
     bool assertEqBytecode = false;
@@ -2087,72 +2092,72 @@ Evaluate(JSContext* cx, unsigned argc, V
     }
 
     return JS_WrapValue(cx, args.rval());
 }
 
 JSString*
 js::shell::FileAsString(JSContext* cx, JS::HandleString pathnameStr)
 {
-    JSAutoByteString pathname(cx, pathnameStr);
+    UniqueChars pathname = JS_EncodeString(cx, pathnameStr);
     if (!pathname)
         return nullptr;
 
     FILE* file;
 
-    file = fopen(pathname.ptr(), "rb");
+    file = fopen(pathname.get(), "rb");
     if (!file) {
-        ReportCantOpenErrorUnknownEncoding(cx, pathname.ptr());
+        ReportCantOpenErrorUnknownEncoding(cx, pathname.get());
         return nullptr;
     }
 
     AutoCloseFile autoClose(file);
 
     if (fseek(file, 0, SEEK_END) != 0) {
-        pathname.clear();
-        if (!pathname.encodeUtf8(cx, pathnameStr))
+        pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+        if (!pathname)
             return nullptr;
-        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.ptr());
+        JS_ReportErrorUTF8(cx, "can't seek end of %s", pathname.get());
         return nullptr;
     }
 
     size_t len = ftell(file);
     if (fseek(file, 0, SEEK_SET) != 0) {
-        pathname.clear();
-        if (!pathname.encodeUtf8(cx, pathnameStr))
+        pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+        if (!pathname)
             return nullptr;
-        JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.ptr());
+        JS_ReportErrorUTF8(cx, "can't seek start of %s", pathname.get());
         return nullptr;
     }
 
     UniqueChars buf(js_pod_malloc<char>(len + 1));
     if (!buf)
         return nullptr;
 
     size_t cc = fread(buf.get(), 1, len, file);
     if (cc != len) {
         if (ptrdiff_t(cc) < 0) {
-            ReportCantOpenErrorUnknownEncoding(cx, pathname.ptr());
+            ReportCantOpenErrorUnknownEncoding(cx, pathname.get());
         } else {
-            pathname.clear();
-            if (!pathname.encodeUtf8(cx, pathnameStr))
+            pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+            if (!pathname)
                 return nullptr;
-            JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.ptr());
+            JS_ReportErrorUTF8(cx, "can't read %s: short read", pathname.get());
         }
         return nullptr;
     }
 
     UniqueTwoByteChars ucbuf(
         JS::LossyUTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(buf.get(), len), &len).get()
     );
     if (!ucbuf) {
-        pathname.clear();
-        if (!pathname.encodeUtf8(cx, pathnameStr))
+        pathname = JS_EncodeStringToUTF8(cx, pathnameStr);
+        if (!pathname)
             return nullptr;
-        JS_ReportErrorUTF8(cx, "Invalid UTF-8 in file '%s'", pathname.ptr());
+        JS_ReportErrorUTF8(cx, "Invalid UTF-8 in file '%s'", pathname.get());
         return nullptr;
     }
 
     return JS_NewUCStringCopyN(cx, ucbuf.get(), len);
 }
 
 /*
  * Function to run scripts and return compilation + execution time. Semantics
@@ -2183,23 +2188,23 @@ Run(JSContext* cx, unsigned argc, Value*
 
     JS::SourceBufferHolder srcBuf(chars.twoByteRange().begin().get(), str->length(),
                                   JS::SourceBufferHolder::NoOwnership);
 
     RootedScript script(cx);
     int64_t startClock = PRMJ_Now();
     {
         /* FIXME: This should use UTF-8 (bug 987069). */
-        JSAutoByteString filename(cx, str);
+        UniqueChars filename = JS_EncodeString(cx, str);
         if (!filename)
             return false;
 
         JS::CompileOptions options(cx);
         options.setIntroductionType("js shell run")
-               .setFileAndLine(filename.ptr(), 1)
+               .setFileAndLine(filename.get(), 1)
                .setIsRunOnce(true)
                .setNoScriptRval(true);
         if (!JS_CompileUCScript(cx, srcBuf, options, &script))
             return false;
     }
 
     if (!JS_ExecuteScript(cx, script))
         return false;
@@ -2335,17 +2340,17 @@ ReadLineBuf(JSContext* cx, unsigned argc
 
     if (args.length() == 1) {
         if (sc->readLineBuf)
             sc->readLineBuf.reset();
 
         RootedString str(cx, JS::ToString(cx, args[0]));
         if (!str)
             return false;
-        sc->readLineBuf = UniqueChars(JS_EncodeStringToUTF8(cx, str));
+        sc->readLineBuf = JS_EncodeStringToUTF8(cx, str);
         if (!sc->readLineBuf)
             return false;
 
         sc->readLineBufPos = 0;
         return true;
     }
 
     JS_ReportErrorASCII(cx, "Must specify at most one argument");
@@ -2361,21 +2366,20 @@ PutStr(JSContext* cx, unsigned argc, Val
         if (!gOutFile->isOpen()) {
             JS_ReportErrorASCII(cx, "output file is closed");
             return false;
         }
 
         RootedString str(cx, JS::ToString(cx, args[0]));
         if (!str)
             return false;
-        char* bytes = JS_EncodeStringToUTF8(cx, str);
+        UniqueChars bytes = JS_EncodeStringToUTF8(cx, str);
         if (!bytes)
             return false;
-        fputs(bytes, gOutFile->fp);
-        JS_free(cx, bytes);
+        fputs(bytes.get(), gOutFile->fp);
         fflush(gOutFile->fp);
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
@@ -2394,21 +2398,20 @@ PrintInternal(JSContext* cx, const CallA
         JS_ReportErrorASCII(cx, "output file is closed");
         return false;
     }
 
     for (unsigned i = 0; i < args.length(); i++) {
         RootedString str(cx, JS::ToString(cx, args[i]));
         if (!str)
             return false;
-        char* bytes = JS_EncodeStringToUTF8(cx, str);
+        UniqueChars bytes = JS_EncodeStringToUTF8(cx, str);
         if (!bytes)
             return false;
-        fprintf(file->fp, "%s%s", i ? " " : "", bytes);
-        JS_free(cx, bytes);
+        fprintf(file->fp, "%s%s", i ? " " : "", bytes.get());
     }
 
     fputc('\n', file->fp);
     fflush(file->fp);
 
     args.rval().setUndefined();
     return true;
 }
@@ -2502,23 +2505,24 @@ StopTimingMutator(JSContext* cx, unsigne
                 mutator_ms, mutator_ms / total_ms * 100.0, gc_ms, gc_ms / total_ms * 100.0);
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static const char*
-ToSource(JSContext* cx, MutableHandleValue vp, JSAutoByteString* bytes)
+ToSource(JSContext* cx, MutableHandleValue vp, UniqueChars* bytes)
 {
     JSString* str = JS_ValueToSource(cx, vp);
     if (str) {
         vp.setString(str);
-        if (bytes->encodeLatin1(cx, str))
-            return bytes->ptr();
+        *bytes = JS_EncodeString(cx, str);
+        if (*bytes)
+            return bytes->get();
     }
     JS_ClearPendingException(cx);
     return "<<error converting value to string>>";
 }
 
 static bool
 AssertEq(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -2533,29 +2537,29 @@ AssertEq(JSContext* cx, unsigned argc, V
                                   "assertEq");
         return false;
     }
 
     bool same;
     if (!JS_SameValue(cx, args[0], args[1], &same))
         return false;
     if (!same) {
-        JSAutoByteString bytes0, bytes1;
+        UniqueChars bytes0, bytes1;
         const char* actual = ToSource(cx, args[0], &bytes0);
         const char* expected = ToSource(cx, args[1], &bytes1);
         if (args.length() == 2) {
             JS_ReportErrorNumberLatin1(cx, my_GetErrorMessage, nullptr, JSSMSG_ASSERT_EQ_FAILED,
                                        actual, expected);
         } else {
-            JSAutoByteString bytes2(cx, args[2].toString());
+            UniqueChars bytes2 = JS_EncodeString(cx, args[2].toString());
             if (!bytes2)
                 return false;
             JS_ReportErrorNumberLatin1(cx, my_GetErrorMessage, nullptr,
                                        JSSMSG_ASSERT_EQ_FAILED_MSG,
-                                       actual, expected, bytes2.ptr());
+                                       actual, expected, bytes2.get());
         }
         return false;
     }
     args.rval().setUndefined();
     return true;
 }
 
 static JSScript*
@@ -3143,30 +3147,30 @@ DisassFile(JSContext* cx, unsigned argc,
         args.rval().setUndefined();
         return true;
     }
 
     // We should change DisassembleOptionParser to store CallArgs.
     JSString* str = JS::ToString(cx, HandleValue::fromMarkedLocation(&p.argv[0]));
     if (!str)
         return false;
-    JSAutoByteString filename(cx, str);
+    UniqueChars filename = JS_EncodeString(cx, str);
     if (!filename)
         return false;
     RootedScript script(cx);
 
     {
         CompileOptions options(cx);
         options.setIntroductionType("js shell disFile")
                .setUTF8(true)
-               .setFileAndLine(filename.ptr(), 1)
+               .setFileAndLine(filename.get(), 1)
                .setIsRunOnce(true)
                .setNoScriptRval(true);
 
-        if (!JS::Compile(cx, options, filename.ptr(), &script))
+        if (!JS::Compile(cx, options, filename.get(), &script))
             return false;
     }
 
     Sprinter sprinter(cx);
     if (!sprinter.init())
         return false;
     bool ok = DisassembleScript(cx, script, nullptr, p.lines, p.recursive, p.sourceNotes, &sprinter);
     if (ok)
@@ -3363,31 +3367,31 @@ static bool
 Crash(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 0)
         MOZ_CRASH("forced crash");
     RootedString message(cx, JS::ToString(cx, args[0]));
     if (!message)
         return false;
-    char* utf8chars = JS_EncodeStringToUTF8(cx, message);
+    UniqueChars utf8chars = JS_EncodeStringToUTF8(cx, message);
     if (!utf8chars)
         return false;
     if (args.get(1).isObject()) {
         RootedValue v(cx);
         RootedObject opts(cx, &args[1].toObject());
         if (!JS_GetProperty(cx, opts, "suppress_minidump", &v))
             return false;
         if (v.isBoolean() && v.toBoolean())
             js::NoteIntentionalCrash();
     }
 #ifndef DEBUG
-    MOZ_ReportCrash(utf8chars, __FILE__, __LINE__);
+    MOZ_ReportCrash(utf8chars.get(), __FILE__, __LINE__);
 #endif
-    MOZ_CRASH_UNSAFE_OOL(utf8chars);
+    MOZ_CRASH_UNSAFE_OOL(utf8chars.get());
 }
 
 static bool
 GetSLX(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedScript script(cx);
 
@@ -4368,17 +4372,17 @@ ParseModule(JSContext* cx, unsigned argc
     if (args.length() > 1) {
         if (!args[1].isString()) {
             const char* typeName = InformalValueTypeName(args[1]);
             JS_ReportErrorASCII(cx, "expected filename string, got %s", typeName);
             return false;
         }
 
         RootedString str(cx, args[1].toString());
-        filename.reset(JS_EncodeString(cx, str));
+        filename = JS_EncodeString(cx, str);
         if (!filename)
             return false;
 
         options.setFileAndLine(filename.get(), 1);
     } else {
         options.setFileAndLine("<string>", 1);
     }
 
@@ -4751,17 +4755,17 @@ BinParse(JSContext* cx, unsigned argc, V
             stringFormat = optionFormat.toString();
             JS::Rooted<JSLinearString*> linearFormat(cx);
             linearFormat = stringFormat->ensureLinear(cx);
             if (StringEqualsAscii(linearFormat, "multipart")) {
                 useMultipart = true;
             } else if (StringEqualsAscii(linearFormat, "simple")) {
                 useMultipart = false;
             } else {
-                JSAutoByteString printable;
+                UniqueChars printable;
                 JS_ReportErrorUTF8(cx,
                                    "Unknown value for option `format`, expected 'multipart' or "
                                    "'simple', got %s",
                                    ValueToPrintableUTF8(cx, optionFormat, &printable));
                 return false;
             }
         } else {
             const char* typeName = InformalValueTypeName(optionFormat);
@@ -4978,17 +4982,17 @@ OffThreadCompileScript(JSContext* cx, un
         return false;
     }
     if (!args[0].isString()) {
         const char* typeName = InformalValueTypeName(args[0]);
         JS_ReportErrorASCII(cx, "expected string to parse, got %s", typeName);
         return false;
     }
 
-    JSAutoByteString fileNameBytes;
+    UniqueChars fileNameBytes;
     CompileOptions options(cx);
     options.setIntroductionType("js shell offThreadCompileScript")
            .setFileAndLine("<string>", 1);
 
     if (args.length() >= 2) {
         if (args[1].isPrimitive()) {
             JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
                                       "evaluate");
@@ -5083,17 +5087,17 @@ OffThreadCompileModule(JSContext* cx, un
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 1 || !args[0].isString()) {
         JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
                                   "offThreadCompileModule");
         return false;
     }
 
-    JSAutoByteString fileNameBytes;
+    UniqueChars fileNameBytes;
     CompileOptions options(cx);
     options.setIntroductionType("js shell offThreadCompileModule")
            .setFileAndLine("<string>", 1);
     options.setIsRunOnce(true)
            .setSourceIsLazy(false);
     options.forceAsync = true;
 
     JSString* scriptContents = args[0].toString();
@@ -5187,17 +5191,17 @@ OffThreadDecodeScript(JSContext* cx, uns
     }
     if (!args[0].isObject() || !CacheEntry_isCacheEntry(&args[0].toObject())) {
         const char* typeName = InformalValueTypeName(args[0]);
         JS_ReportErrorASCII(cx, "expected cache entry, got %s", typeName);
         return false;
     }
     RootedObject cacheEntry(cx, &args[0].toObject());
 
-    JSAutoByteString fileNameBytes;
+    UniqueChars fileNameBytes;
     CompileOptions options(cx);
     options.setIntroductionType("js shell offThreadDecodeScript")
            .setFileAndLine("<string>", 1);
 
     if (args.length() >= 2) {
         if (args[1].isPrimitive()) {
             JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS,
                                       "evaluate");
@@ -5416,17 +5420,17 @@ NestedShell(JSContext* cx, unsigned argc
 
     // The arguments to nestedShell are stringified and append to argv.
     RootedString str(cx);
     for (unsigned i = 0; i < args.length(); i++) {
         str = ToString(cx, args[i]);
         if (!str)
             return false;
 
-        UniqueChars arg(JS_EncodeString(cx, str));
+        UniqueChars arg = JS_EncodeString(cx, str);
         if (!arg || !argv.append(std::move(arg)))
             return false;
 
         // As a special case, if the caller passes "--js-cache", replace that
         // with "--js-cache=$(jsCacheDir)"
         if (!strcmp(argv.back(), "--js-cache") && jsCacheDir) {
             UniqueChars newArg = JS_smprintf("--js-cache=%s", jsCacheDir);
             if (!newArg) {
@@ -6956,17 +6960,17 @@ class ShellAutoEntryMonitor : JS::dbg::A
 
     void Entry(JSContext* cx, JSFunction* function, JS::HandleValue asyncStack,
                const char* asyncCause) override {
         MOZ_ASSERT(!enteredWithoutExit);
         enteredWithoutExit = true;
 
         RootedString displayId(cx, JS_GetFunctionDisplayId(function));
         if (displayId) {
-            UniqueChars displayIdStr(JS_EncodeStringToUTF8(cx, displayId));
+            UniqueChars displayIdStr = JS_EncodeStringToUTF8(cx, displayId);
             if (!displayIdStr) {
                 // We report OOM in buildResult.
                 cx->recoverFromOutOfMemory();
                 oom = true;
                 return;
             }
             oom = !log.append(std::move(displayIdStr));
             return;
@@ -7154,21 +7158,21 @@ SetARMHwCapFlags(JSContext* cx, unsigned
         return false;
     }
 
     RootedString flagsListString(cx, JS::ToString(cx, args.get(0)));
     if (!flagsListString)
         return false;
 
 #if defined(JS_CODEGEN_ARM)
-    JSAutoByteString flagsList(cx, flagsListString);
+    UniqueChars flagsList = JS_EncodeString(cx, flagsListString);
     if (!flagsList)
         return false;
 
-    jit::ParseARMHwCapFlags(flagsList.ptr());
+    jit::ParseARMHwCapFlags(flagsList.get());
 #endif
 
     args.rval().setUndefined();
     return true;
 }
 
 #ifndef __AFL_HAVE_MANUAL_CONTROL
 # define __AFL_LOOP(x) true
@@ -8192,17 +8196,17 @@ PrintStackTrace(JSContext* cx, HandleVal
     if (!stackObj)
         return true;
 
     JSPrincipals* principals = exnObj->as<ErrorObject>().realm()->principals();
     RootedString stackStr(cx);
     if (!BuildStackString(cx, principals, stackObj, &stackStr, 2))
         return false;
 
-    UniqueChars stack(JS_EncodeStringToUTF8(cx, stackStr));
+    UniqueChars stack = JS_EncodeStringToUTF8(cx, stackStr);
     if (!stack)
         return false;
 
     FILE* fp = ErrorFilePointer();
     fputs("Stack:\n", fp);
     fputs(stack.get(), fp);
 
     return true;
@@ -9051,17 +9055,17 @@ ProcessArgs(JSContext* cx, OptionParser*
         RootedString jspath(cx, JS_NewStringCopyZ(cx, path));
         if (!jspath)
             return false;
 
         JSString* absolutePath = js::shell::ResolvePath(cx, jspath, RootRelative);
         if (!absolutePath)
             return false;
 
-        sc->moduleLoadPath = UniqueChars(JS_EncodeString(cx, absolutePath));
+        sc->moduleLoadPath = JS_EncodeString(cx, absolutePath);
     } else {
         sc->moduleLoadPath = js::shell::GetCWD();
     }
 
     if (!sc->moduleLoadPath)
         return false;
 
     if (!modulePaths.empty() && !InitModuleLoader(cx))
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -27,17 +27,16 @@
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/String.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/SourceNotes.h"
 #include "gc/FreeOp.h"
 #include "gc/GCInternals.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 #include "js/Printf.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/CodeCoverage.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
@@ -1127,81 +1126,83 @@ js::DumpScript(JSContext* cx, JSScript* 
         return false;
     RootedScript script(cx, scriptArg);
     bool ok = Disassemble(cx, script, true, &sprinter);
     fprintf(fp, "%s", sprinter.string());
     return ok;
 }
 
 static bool
-ToDisassemblySource(JSContext* cx, HandleValue v, JSAutoByteString* bytes)
+ToDisassemblySource(JSContext* cx, HandleValue v, UniqueChars* bytes)
 {
     if (v.isString()) {
         Sprinter sprinter(cx);
         if (!sprinter.init())
             return false;
         char* nbytes = QuoteString(&sprinter, v.toString(), '"');
         if (!nbytes)
             return false;
         UniqueChars copy = JS_smprintf("%s", nbytes);
         if (!copy) {
             ReportOutOfMemory(cx);
             return false;
         }
-        bytes->initBytes(std::move(copy));
+        *bytes = std::move(copy);
         return true;
     }
 
     if (JS::RuntimeHeapIsBusy()) {
         UniqueChars source = JS_smprintf("<value>");
         if (!source) {
             ReportOutOfMemory(cx);
             return false;
         }
-        bytes->initBytes(std::move(source));
+        *bytes = std::move(source);
         return true;
     }
 
     if (v.isObject()) {
         JSObject& obj = v.toObject();
 
         if (obj.is<JSFunction>()) {
             RootedFunction fun(cx, &obj.as<JSFunction>());
             JSString* str = JS_DecompileFunction(cx, fun);
             if (!str)
                 return false;
-            return bytes->encodeLatin1(cx, str);
+            *bytes = JS_EncodeString(cx, str);
+            return !!*bytes;
         }
 
         if (obj.is<RegExpObject>()) {
             JSString* source = obj.as<RegExpObject>().toString(cx);
             if (!source)
                 return false;
-            return bytes->encodeLatin1(cx, source);
+            *bytes = JS_EncodeString(cx, source);
+            return !!*bytes;
         }
     }
 
     return !!ValueToPrintableLatin1(cx, v, bytes, true);
 }
 
 static bool
-ToDisassemblySource(JSContext* cx, HandleScope scope, JSAutoByteString* bytes)
+ToDisassemblySource(JSContext* cx, HandleScope scope, UniqueChars* bytes)
 {
     UniqueChars source = JS_smprintf("%s {", ScopeKindString(scope->kind()));
     if (!source) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
-        JSAutoByteString nameBytes;
+        UniqueChars nameBytes;
         if (!AtomToPrintableString(cx, bi.name(), &nameBytes))
             return false;
 
-        source = JS_sprintf_append(std::move(source), "%s: ", nameBytes.ptr());
+        source = JS_sprintf_append(std::move(source), "%s: ", nameBytes.get());
         if (!source) {
             ReportOutOfMemory(cx);
             return false;
         }
 
         BindingLocation loc = bi.location();
         switch (loc.kind()) {
           case BindingLocation::Kind::Global:
@@ -1244,17 +1245,17 @@ ToDisassemblySource(JSContext* cx, Handl
     }
 
     source = JS_sprintf_append(std::move(source), "}");
     if (!source) {
         ReportOutOfMemory(cx);
         return false;
     }
 
-    bytes->initBytes(std::move(source));
+    *bytes = std::move(source);
     return true;
 }
 
 static bool
 DumpJumpOrigins(HandleScript script, jsbytecode* pc, const BytecodeParser* parser, Sprinter* sp)
 {
     bool called = false;
     auto callback = [&script, &sp, &called](jsbytecode* pc, BytecodeParser::JumpKind kind) {
@@ -1416,83 +1417,83 @@ Disassemble1(JSContext* cx, HandleScript
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
         if (!sp->jsprintf(" %u (%+d)", unsigned(loc + int(off)), int(off)))
             return 0;
         break;
       }
 
       case JOF_SCOPE: {
         RootedScope scope(cx, script->getScope(GET_UINT32_INDEX(pc)));
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!ToDisassemblySource(cx, scope, &bytes))
             return 0;
-        if (!sp->jsprintf(" %s", bytes.ptr()))
+        if (!sp->jsprintf(" %s", bytes.get()))
             return 0;
         break;
       }
 
       case JOF_ENVCOORD: {
         RootedValue v(cx,
             StringValue(EnvironmentCoordinateName(cx->caches().envCoordinateNameCache, script, pc)));
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
         EnvironmentCoordinate ec(pc);
-        if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.ptr(), ec.hops(), ec.slot()))
+        if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(), ec.slot()))
             return 0;
         break;
       }
 
       case JOF_ATOM: {
         RootedValue v(cx, StringValue(script->getAtom(GET_UINT32_INDEX(pc))));
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (!sp->jsprintf(" %s", bytes.ptr()))
+        if (!sp->jsprintf(" %s", bytes.get()))
             return 0;
         break;
       }
 
       case JOF_DOUBLE: {
         RootedValue v(cx, script->getConst(GET_UINT32_INDEX(pc)));
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (!sp->jsprintf(" %s", bytes.ptr()))
+        if (!sp->jsprintf(" %s", bytes.get()))
             return 0;
         break;
       }
 
       case JOF_OBJECT: {
         /* Don't call obj.toSource if analysis/inference is active. */
         if (script->zone()->types.activeAnalysis) {
             if (!sp->jsprintf(" object"))
                 return 0;
             break;
         }
 
         JSObject* obj = script->getObject(GET_UINT32_INDEX(pc));
         {
-            JSAutoByteString bytes;
+            UniqueChars bytes;
             RootedValue v(cx, ObjectValue(*obj));
             if (!ToDisassemblySource(cx, v, &bytes))
                 return 0;
-            if (!sp->jsprintf(" %s", bytes.ptr()))
+            if (!sp->jsprintf(" %s", bytes.get()))
                 return 0;
         }
         break;
       }
 
       case JOF_REGEXP: {
         js::RegExpObject* obj = script->getRegExp(pc);
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         RootedValue v(cx, ObjectValue(*obj));
         if (!ToDisassemblySource(cx, v, &bytes))
             return 0;
-        if (!sp->jsprintf(" %s", bytes.ptr()))
+        if (!sp->jsprintf(" %s", bytes.get()))
             return 0;
         break;
       }
 
       case JOF_TABLESWITCH:
       {
         int32_t i, low, high;
 
@@ -2312,17 +2313,17 @@ js::DecompileValueGenerator(JSContext* c
     if (!fallback) {
         if (v.isUndefined())
             return DuplicateString(cx, js_undefined_str); // Prevent users from seeing "(void 0)"
         fallback = ValueToSource(cx, v);
         if (!fallback)
             return nullptr;
     }
 
-    return UniqueChars(JS_EncodeString(cx, fallback));
+    return JS_EncodeString(cx, fallback);
 }
 
 static bool
 DecompileArgumentFromStack(JSContext* cx, int formalIndex, UniqueChars* res)
 {
     MOZ_ASSERT(formalIndex >= 0);
 
     *res = nullptr;
@@ -2402,17 +2403,17 @@ js::DecompileArgument(JSContext* cx, int
     }
     if (v.isUndefined())
         return DuplicateString(cx, js_undefined_str); // Prevent users from seeing "(void 0)"
 
     RootedString fallback(cx, ValueToSource(cx, v));
     if (!fallback)
         return nullptr;
 
-    return UniqueChars(JS_EncodeString(cx, fallback));
+    return JS_EncodeString(cx, fallback);
 }
 
 extern bool
 js::IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset)
 {
     // This could be faster (by following jump instructions if the target is <= offset).
     for (BytecodeRange r(cx, script); !r.empty(); r.popFront()) {
         size_t here = r.frontOffset();
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -20,17 +20,17 @@
 #include "frontend/Parser.h"
 #include "gc/FreeOp.h"
 #include "gc/HashUtil.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "gc/PublicIterators.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Date.h"
 #include "js/SourceBufferHolder.h"
 #include "js/StableStringChars.h"
 #include "js/UbiNodeBreadthFirst.h"
 #include "js/Vector.h"
 #include "js/Wrapper.h"
 #include "proxy/ScriptedProxyHandler.h"
 #include "util/Text.h"
@@ -481,20 +481,20 @@ ParseEvalOptions(JSContext* cx, HandleVa
 
     RootedValue v(cx);
     if (!JS_GetProperty(cx, opts, "url", &v))
         return false;
     if (!v.isUndefined()) {
         RootedString url_str(cx, ToString<CanGC>(cx, v));
         if (!url_str)
             return false;
-        JSAutoByteString url_bytes(cx, url_str);
+        UniqueChars url_bytes = JS_EncodeString(cx, url_str);
         if (!url_bytes)
             return false;
-        if (!options.setFilename(cx, url_bytes.ptr()))
+        if (!options.setFilename(cx, url_bytes.get()))
             return false;
     }
 
     if (!JS_GetProperty(cx, opts, "lineNumber", &v))
         return false;
     if (!v.isUndefined()) {
         uint32_t lineno;
         if (!ToUint32(cx, v, &lineno))
@@ -4476,17 +4476,17 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
 
     /* A script must be in one of these realms to match the query. */
     RealmSet realms;
 
     /* If this is a string, matching scripts have urls equal to it. */
     RootedValue url;
 
     /* url as a C string. */
-    JSAutoByteString urlCString;
+    UniqueChars urlCString;
 
     /* If this is a string, matching scripts' sources have displayURLs equal to
      * it. */
     RootedLinearString displayURLString;
 
     /*
      * If this is a source referent, matching scripts will have sources equal
      * to this instance. Ideally we'd use a Maybe here, but Maybe interacts
@@ -4562,17 +4562,18 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
     /*
      * Given that parseQuery or omittedQuery has been called, prepare to match
      * scripts. Set urlCString and displayURLChars as appropriate.
      */
     bool prepareQuery() {
         // Compute urlCString and displayURLChars, if a url or displayURL was
         // given respectively.
         if (url.isString()) {
-            if (!urlCString.encodeLatin1(cx, url.toString()))
+            urlCString = JS_EncodeString(cx, url.toString());
+            if (!urlCString)
                 return false;
         }
 
         return true;
     }
 
     bool delazifyScripts() {
         // All scripts in debuggee realms must be visible, so delazify
@@ -4603,24 +4604,24 @@ class MOZ_STACK_CLASS Debugger::ScriptQu
         //
         // * hasLine
         //   Only JSScript supports GetScriptLineExtent.
         return innermost || hasLine;
     }
 
     template <typename T>
     MOZ_MUST_USE bool commonFilter(T script, const JS::AutoRequireNoGC& nogc) {
-        if (urlCString.ptr()) {
+        if (urlCString) {
             bool gotFilename = false;
-            if (script->filename() && strcmp(script->filename(), urlCString.ptr()) == 0)
+            if (script->filename() && strcmp(script->filename(), urlCString.get()) == 0)
                 gotFilename = true;
 
             bool gotSourceURL = false;
             if (!gotFilename && script->scriptSource()->introducerFilename() &&
-                strcmp(script->scriptSource()->introducerFilename(), urlCString.ptr()) == 0)
+                strcmp(script->scriptSource()->introducerFilename(), urlCString.get()) == 0)
             {
                 gotSourceURL = true;
             }
             if (!gotFilename && !gotSourceURL)
                 return false;
         }
         if (displayURLString) {
             if (!script->scriptSource() || !script->scriptSource()->hasDisplayURL())
@@ -4915,17 +4916,17 @@ class MOZ_STACK_CLASS Debugger::ObjectQu
 
         if (!referent.is<JSObject>() || referent.exposeToJS().isUndefined())
             return true;
 
         JSObject* obj = referent.as<JSObject>();
 
         if (!className.isUndefined()) {
             const char* objClassName = obj->getClass()->name;
-            if (strcmp(objClassName, classNameCString.ptr()) != 0)
+            if (strcmp(objClassName, classNameCString.get()) != 0)
                 return true;
         }
 
         return objects.append(obj);
     }
 
   private:
     /* The context in which we should do our work. */
@@ -4936,25 +4937,26 @@ class MOZ_STACK_CLASS Debugger::ObjectQu
 
     /*
      * If this is non-null, matching objects will have a class whose name is
      * this property.
      */
     RootedValue className;
 
     /* The className member, as a C string. */
-    JSAutoByteString classNameCString;
+    UniqueChars classNameCString;
 
     /*
      * Given that either omittedQuery or parseQuery has been called, prepare the
      * query for matching objects.
      */
     bool prepareQuery() {
         if (className.isString()) {
-            if (!classNameCString.encodeLatin1(cx, className.toString()))
+            classNameCString = JS_EncodeString(cx, className.toString());
+            if (!classNameCString)
                 return false;
         }
 
         return true;
     }
 };
 
 bool
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -3,17 +3,16 @@
  * 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 "vm/EnvironmentObject-inl.h"
 
 #include "builtin/ModuleObject.h"
 #include "gc/Policy.h"
-#include "js/AutoByteString.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/AsyncFunction.h"
 #include "vm/GlobalObject.h"
 #include "vm/Iteration.h"
 #include "vm/ProxyObject.h"
 #include "vm/Realm.h"
 #include "vm/Shape.h"
 #include "vm/Xdr.h"
@@ -1410,20 +1409,20 @@ LiveEnvironmentVal::staticAsserts()
 
 /*****************************************************************************/
 
 namespace {
 
 static void
 ReportOptimizedOut(JSContext* cx, HandleId id)
 {
-    JSAutoByteString printable;
+    UniqueChars printable;
     if (ValueToPrintableLatin1(cx, IdToValue(id), &printable)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_OPTIMIZED_OUT,
-                                   printable.ptr());
+                                   printable.get());
     }
 }
 
 /*
  * DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy
  * objects. Having a custom handler (rather than trying to reuse js::Wrapper)
  * gives us several important abilities:
  *  - We want to pass the EnvironmentObject as the receiver to forwarded scope
@@ -3354,21 +3353,21 @@ js::CheckVarNameConflict(JSContext* cx, 
         return false;
     }
     return true;
 }
 
 static void
 ReportCannotDeclareGlobalBinding(JSContext* cx, HandlePropertyName name, const char* reason)
 {
-    JSAutoByteString printable;
+    UniqueChars printable;
     if (AtomToPrintableString(cx, name, &printable)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                                    JSMSG_CANT_DECLARE_GLOBAL_BINDING,
-                                   printable.ptr(), reason);
+                                   printable.get(), reason);
     }
 }
 
 bool
 js::CheckCanDeclareGlobalBinding(JSContext* cx, Handle<GlobalObject*> global,
                                  HandlePropertyName name, bool isFunction)
 {
     RootedId id(cx, NameToId(name));
--- a/js/src/vm/ErrorObject.cpp
+++ b/js/src/vm/ErrorObject.cpp
@@ -8,17 +8,16 @@
 #include "vm/ErrorObject-inl.h"
 
 #include "mozilla/Range.h"
 
 #include <utility>
 
 #include "jsexn.h"
 
-#include "js/AutoByteString.h"
 #include "js/CallArgs.h"
 #include "js/CharacterEncoding.h"
 #include "vm/GlobalObject.h"
 #include "vm/SelfHosting.h"
 #include "vm/StringType.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
@@ -141,20 +140,20 @@ js::ErrorObject::getOrCreateErrorReport(
     // the nitty-gritty malloc stuff.
     JSErrorReport report;
 
     // Type.
     JSExnType type_ = type();
     report.exnType = type_;
 
     // Filename.
-    JSAutoByteString filenameStr;
-    if (!filenameStr.encodeLatin1(cx, fileName(cx)))
+    UniqueChars filenameStr = JS_EncodeString(cx, fileName(cx));
+    if (!filenameStr)
         return nullptr;
-    report.filename = filenameStr.ptr();
+    report.filename = filenameStr.get();
 
     // Coordinates.
     report.lineno = lineNumber();
     report.column = columnNumber();
 
     // Message. Note that |new Error()| will result in an undefined |message|
     // slot, so we need to explicitly substitute the empty string in that case.
     RootedString message(cx, getMessage());
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -26,17 +26,17 @@
 #include "builtin/ModuleObject.h"
 #include "builtin/Promise.h"
 #include "builtin/String.h"
 #include "jit/AtomicOperations.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/Jit.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "util/StringBuffer.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
 #ifdef ENABLE_BIGINT
 #include "vm/BigIntType.h"
 #endif
 #include "vm/BytecodeUtil.h"
 #include "vm/Debugger.h"
@@ -1856,17 +1856,17 @@ js::ReportInNotObjectError(JSContext* cx
             if (!buf.appendSubstring(str, 0, MaxStringLength))
                 return nullptr;
             if (!buf.append("..."))
                 return nullptr;
             str = buf.finishString();
             if (!str)
                 return nullptr;
         }
-        return UniqueChars(JS_EncodeString(cx, str));
+        return JS_EncodeString(cx, str);
     };
 
     if (lref.isString() && rref.isString()) {
         UniqueChars lbytes = uniqueCharsFromString(cx, lref);
         if (!lbytes)
             return;
         UniqueChars rbytes = uniqueCharsFromString(cx, rref);
         if (!rbytes)
@@ -5334,19 +5334,19 @@ js::NewArrayOperationWithTemplate(JSCont
     return obj;
 }
 
 void
 js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandleId id)
 {
     MOZ_ASSERT(errorNumber == JSMSG_UNINITIALIZED_LEXICAL ||
                errorNumber == JSMSG_BAD_CONST_ASSIGN);
-    JSAutoByteString printable;
+    UniqueChars printable;
     if (ValueToPrintableLatin1(cx, IdToValue(id), &printable))
-        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, printable.ptr());
+        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, printable.get());
 }
 
 void
 js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber, HandlePropertyName name)
 {
     RootedId id(cx, NameToId(name));
     ReportRuntimeLexicalError(cx, errorNumber, id);
 }
@@ -5377,20 +5377,20 @@ js::ReportRuntimeLexicalError(JSContext*
     }
 
     ReportRuntimeLexicalError(cx, errorNumber, name);
 }
 
 void
 js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name, const char* redeclKind)
 {
-    JSAutoByteString printable;
+    UniqueChars printable;
     if (AtomToPrintableString(cx, name, &printable)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_REDECLARED_VAR,
-                                   redeclKind, printable.ptr());
+                                   redeclKind, printable.get());
     }
 }
 
 bool
 js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
 {
     switch (kind) {
       case CheckIsObjectKind::IteratorNext:
@@ -5456,21 +5456,21 @@ js::ThrowUninitializedThis(JSContext* cx
                 break;
             }
         }
         MOZ_ASSERT(fun);
     }
 
     if (fun->isDerivedClassConstructor()) {
         const char* name = "anonymous";
-        JSAutoByteString str;
+        UniqueChars str;
         if (fun->explicitName()) {
             if (!AtomToPrintableString(cx, fun->explicitName(), &str))
                 return false;
-            name = str.ptr();
+            name = str.get();
         }
 
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_THIS, name);
         return false;
     }
 
     MOZ_ASSERT(fun->isArrow());
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_THIS_ARROW);
--- a/js/src/vm/JSAtom.cpp
+++ b/js/src/vm/JSAtom.cpp
@@ -16,17 +16,17 @@
 #include "mozilla/Unused.h"
 
 #include <string.h>
 
 #include "jstypes.h"
 
 #include "builtin/String.h"
 #include "gc/Marking.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "util/Text.h"
 #include "vm/JSContext.h"
 #include "vm/SymbolType.h"
 #include "vm/Xdr.h"
 
 #include "gc/AtomMarking-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSObject-inl.h"
@@ -112,23 +112,23 @@ js::AtomStateEntry::asPtr(JSContext* cx)
 {
     JSAtom* atom = asPtrUnbarriered();
     if (!cx->helperThread())
         JSString::readBarrier(atom);
     return atom;
 }
 
 const char*
-js::AtomToPrintableString(JSContext* cx, JSAtom* atom, JSAutoByteString* bytes)
+js::AtomToPrintableString(JSContext* cx, JSAtom* atom, UniqueChars* bytes)
 {
     JSString* str = QuoteString(cx, atom, 0);
     if (!str)
         return nullptr;
-    bytes->initBytes(EncodeLatin1(cx, str));
-    return bytes->ptr();
+    *bytes = EncodeLatin1(cx, str);
+    return bytes->get();
 }
 
 #define DEFINE_PROTO_STRING(name,init,clasp) const char js_##name##_str[] = #name;
 JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING)
 #undef DEFINE_PROTO_STRING
 
 #define CONST_CHAR_STR(idpart, id, text) const char js_##idpart##_str[] = text;
 FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR)
--- a/js/src/vm/JSAtom.h
+++ b/js/src/vm/JSAtom.h
@@ -6,28 +6,27 @@
 
 #ifndef vm_JSAtom_h
 #define vm_JSAtom_h
 
 #include "mozilla/Maybe.h"
 
 #include "gc/Rooting.h"
 #include "js/TypeDecls.h"
+#include "js/Utility.h"
 #include "vm/CommonPropertyNames.h"
 
-class JSAutoByteString;
-
 namespace js {
 
 /*
  * Return a printable, lossless char[] representation of a string-type atom.
  * The lifetime of the result matches the lifetime of bytes.
  */
 extern const char*
-AtomToPrintableString(JSContext* cx, JSAtom* atom, JSAutoByteString* bytes);
+AtomToPrintableString(JSContext* cx, JSAtom* atom, UniqueChars* bytes);
 
 class PropertyName;
 
 }  /* namespace js */
 
 /* Well-known predefined C strings. */
 #define DECLARE_PROTO_STR(name,init,clasp) extern const char js_##name##_str[];
 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -32,17 +32,16 @@
 #include "jspubtd.h"
 #include "jstypes.h"
 
 #include "builtin/String.h"
 #include "gc/FreeOp.h"
 #include "gc/Marking.h"
 #include "jit/Ion.h"
 #include "jit/PcScriptCache.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 #include "js/Printf.h"
 #ifdef JS_SIMULATOR_ARM64
 # include "jit/arm64/vixl/Simulator-vixl.h"
 #endif
 #ifdef JS_SIMULATOR_ARM
 # include "jit/arm/Simulator-arm.h"
 #endif
@@ -437,20 +436,20 @@ js::ReportUsageErrorASCII(JSContext* cx,
     RootedValue usage(cx);
     if (!JS_GetProperty(cx, callee, "usage", &usage))
         return;
 
     if (!usage.isString()) {
         JS_ReportErrorASCII(cx, "%s", msg);
     } else {
         RootedString usageStr(cx, usage.toString());
-        JSAutoByteString str;
-        if (!str.encodeUtf8(cx, usageStr))
+        UniqueChars str = JS_EncodeStringToUTF8(cx, usageStr);
+        if (!str)
             return;
-        JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.ptr());
+        JS_ReportErrorUTF8(cx, "%s. Usage: %s", msg, str.get());
     }
 }
 
 enum class PrintErrorKind {
     Error,
     Warning,
     StrictWarning,
     Note
@@ -888,20 +887,20 @@ js::ReportErrorNumberUCArray(JSContext* 
     ReportError(cx, &report, callback, userRef);
 
     return warning;
 }
 
 void
 js::ReportIsNotDefined(JSContext* cx, HandleId id)
 {
-    JSAutoByteString printable;
+    UniqueChars printable;
     if (!ValueToPrintableUTF8(cx, IdToValue(id), &printable))
         return;
-    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, printable.ptr());
+    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_NOT_DEFINED, printable.get());
 }
 
 void
 js::ReportIsNotDefined(JSContext* cx, HandlePropertyName name)
 {
     RootedId id(cx, NameToId(name));
     ReportIsNotDefined(cx, id);
 }
@@ -929,58 +928,58 @@ js::ReportIsNullOrUndefinedForPropertyAc
                                    bytes.get(), js_undefined_str);
     } else {
         MOZ_ASSERT(v.isNull());
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
                                    bytes.get(), js_null_str);
     }
 }
 
-char*
-EncodeIdAsLatin1(JSContext* cx, HandleId id, JSAutoByteString& bytes)
+static UniqueChars
+EncodeIdAsLatin1(JSContext* cx, HandleId id)
 {
     RootedValue idVal(cx, IdToValue(id));
-    RootedString idStr(cx, ValueToSource(cx, idVal));
+    JSString* idStr = ValueToSource(cx, idVal);
     if (!idStr)
         return nullptr;
 
-    return bytes.encodeLatin1(cx, idStr);
+    return EncodeLatin1(cx, idStr);
 }
 
 void
 js::ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx, HandleValue v, HandleId key,
                                              bool reportScanStack)
 {
     MOZ_ASSERT(v.isNullOrUndefined());
 
-    JSAutoByteString keyBytes;
-    if (!EncodeIdAsLatin1(cx, key, keyBytes))
+    UniqueChars keyBytes = EncodeIdAsLatin1(cx, key);
+    if (!keyBytes)
         return;
 
     if (!reportScanStack) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL,
-                                   keyBytes.ptr(),
+                                   keyBytes.get(),
                                    v.isUndefined() ? js_undefined_str : js_null_str);
         return;
     }
 
     UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, nullptr);
     if (!bytes)
         return;
 
     if (strcmp(bytes.get(), js_undefined_str) == 0 || strcmp(bytes.get(), js_null_str) == 0) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL,
-                                   keyBytes.ptr(), bytes.get());
+                                   keyBytes.get(), bytes.get());
     } else if (v.isUndefined()) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL_EXPR,
-                                   bytes.get(), js_undefined_str, keyBytes.ptr());
+                                   bytes.get(), js_undefined_str, keyBytes.get());
     } else {
         MOZ_ASSERT(v.isNull());
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL_EXPR,
-                                   bytes.get(), js_null_str, keyBytes.ptr());
+                                   bytes.get(), js_null_str, keyBytes.get());
     }
 }
 
 void
 js::ReportMissingArg(JSContext* cx, HandleValue v, unsigned arg)
 {
     char argbuf[11];
     UniqueChars bytes;
--- a/js/src/vm/JSFunction-inl.h
+++ b/js/src/vm/JSFunction-inl.h
@@ -6,29 +6,30 @@
 
 #ifndef vm_JSFunction_inl_h
 #define vm_JSFunction_inl_h
 
 #include "vm/JSFunction.h"
 
 #include "gc/Allocator.h"
 #include "gc/GCTrace.h"
+#include "js/CharacterEncoding.h"
 #include "vm/EnvironmentObject.h"
 
 #include "vm/JSObject-inl.h"
 
-class JSAutoByteString;
-
 namespace js {
 
 inline const char*
-GetFunctionNameBytes(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
+GetFunctionNameBytes(JSContext* cx, JSFunction* fun, UniqueChars* bytes)
 {
-    if (JSAtom* name = fun->explicitName())
-        return bytes->encodeLatin1(cx, name);
+    if (JSAtom* name = fun->explicitName()) {
+        *bytes = JS_EncodeString(cx, name);
+        return bytes->get();
+    }
     return js_anonymous_str;
 }
 
 inline bool
 CanReuseFunctionForClone(JSContext* cx, HandleFunction fun)
 {
     if (!fun->isSingleton())
         return false;
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -26,17 +26,16 @@
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/String.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/TokenStream.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "jit/InlinableNatives.h"
 #include "jit/Ion.h"
-#include "js/AutoByteString.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/CompileOptions.h"
 #include "js/Proxy.h"
 
 #include "js/SourceBufferHolder.h"
 #include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
@@ -2494,29 +2493,29 @@ js::ReportIncompatibleMethod(JSContext* 
     } else if (thisv.isSymbol()) {
         MOZ_ASSERT(clasp != &SymbolObject::class_);
     } else {
         MOZ_ASSERT(thisv.isUndefined() || thisv.isNull());
     }
 #endif
 
     if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
-        JSAutoByteString funNameBytes;
+        UniqueChars funNameBytes;
         if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
                                        clasp->name, funName, InformalValueTypeName(thisv));
         }
     }
 }
 
 void
 js::ReportIncompatible(JSContext* cx, const CallArgs& args)
 {
     if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) {
-        JSAutoByteString funNameBytes;
+        UniqueChars funNameBytes;
         if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
                                        funName, "method", InformalValueTypeName(args.thisv()));
         }
     }
 }
 
 namespace JS {
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -30,17 +30,17 @@
 #endif
 #include "builtin/Eval.h"
 #include "builtin/Object.h"
 #include "builtin/String.h"
 #include "builtin/Symbol.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Policy.h"
 #include "jit/BaselineJIT.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/MemoryMetrics.h"
 #include "js/Proxy.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "js/Wrapper.h"
 #include "util/Text.h"
 #include "util/Windows.h"
 #include "vm/ArgumentsObject.h"
@@ -90,29 +90,29 @@ js::ReportNotObject(JSContext* cx, const
                                    bytes.get());
 }
 
 void
 js::ReportNotObjectArg(JSContext* cx, const char* nth, const char* fun, HandleValue v)
 {
     MOZ_ASSERT(!v.isObject());
 
-    JSAutoByteString bytes;
+    UniqueChars bytes;
     if (const char* chars = ValueToSourceForError(cx, v, bytes)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT_ARG,
                                    nth, fun, chars);
     }
 }
 
 void
 js::ReportNotObjectWithName(JSContext* cx, const char* name, HandleValue v)
 {
     MOZ_ASSERT(!v.isObject());
 
-    JSAutoByteString bytes;
+    UniqueChars bytes;
     if (const char* chars = ValueToSourceForError(cx, v, bytes)) {
         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT_NAME,
                                    name, chars);
     }
 }
 
 JS_PUBLIC_API(const char*)
 JS::InformalValueTypeName(const Value& v)
@@ -256,25 +256,25 @@ bool
 js::Throw(JSContext* cx, jsid id, unsigned errorNumber, const char* details)
 {
     MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == (details ? 2 : 1));
 
     RootedValue idVal(cx, IdToValue(id));
     JSString* idstr = ValueToSource(cx, idVal);
     if (!idstr)
        return false;
-    JSAutoByteString bytes(cx, idstr);
+    UniqueChars bytes = JS_EncodeString(cx, idstr);
     if (!bytes)
         return false;
 
     if (details) {
-        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr(),
+        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.get(),
                                    details);
     } else {
-        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr());
+        JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.get());
     }
 
     return false;
 }
 
 
 /*** PropertyDescriptor operations and DefineProperties ******************************************/
 
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -7,17 +7,17 @@
 #include "vm/NativeObject-inl.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 
 #include "gc/Marking.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Value.h"
 #include "vm/Debugger.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/ArrayObject-inl.h"
 #include "vm/EnvironmentObject-inl.h"
@@ -2470,21 +2470,21 @@ MaybeReportUndeclaredVarAssignment(JSCon
         if (IsStrictSetPC(pc))
             flags = JSREPORT_ERROR;
         else if (cx->realm()->behaviors().extraWarnings(cx))
             flags = JSREPORT_WARNING | JSREPORT_STRICT;
         else
             return true;
     }
 
-    JSAutoByteString bytes;
-    if (!bytes.encodeUtf8(cx, propname))
+    UniqueChars bytes = JS_EncodeStringToUTF8(cx, propname);
+    if (!bytes)
         return false;
     return JS_ReportErrorFlagsAndNumberUTF8(cx, flags, GetErrorMessage, nullptr,
-                                            JSMSG_UNDECLARED_VAR, bytes.ptr());
+                                            JSMSG_UNDECLARED_VAR, bytes.get());
 }
 
 /*
  * Finish assignment to a shapeful data property of a native object obj. This
  * conforms to no standard and there is a lot of legacy baggage here.
  */
 static bool
 NativeSetExistingDataProperty(JSContext* cx, HandleNativeObject obj, HandleShape shape,
--- a/js/src/vm/Probes.cpp
+++ b/js/src/vm/Probes.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "vm/Probes-inl.h"
 
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "vm/JSContext.h"
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "vm/JSScript-inl.h"
 #endif
 
 #define TYPEOF(cx,v)    (v.isNull() ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
 
@@ -29,40 +29,41 @@ ScriptFilename(const JSScript* script)
     if (!script)
         return probes::nullName;
     if (!script->filename())
         return probes::anonymousName;
     return script->filename();
 }
 
 static const char*
-FunctionName(JSContext* cx, JSFunction* fun, JSAutoByteString* bytes)
+FunctionName(JSContext* cx, JSFunction* fun, UniqueChars* bytes)
 {
     if (!fun)
         return probes::nullName;
     if (!fun->displayAtom())
         return probes::anonymousName;
-    return bytes->encodeLatin1(cx, fun->displayAtom()) ? bytes->ptr() : probes::nullName;
+    *bytes = JS_EncodeString(cx, fun->displayAtom());
+    return *bytes ? bytes->get() : probes::nullName;
 }
 
 /*
  * These functions call the DTrace macros for the JavaScript USDT probes.
  * Originally this code was inlined in the JavaScript code; however since
  * a number of operations are called, these have been placed into functions
  * to reduce any negative compiler optimization effect that the addition of
  * a number of usually unused lines of code would cause.
  */
 void
 probes::DTraceEnterJSFun(JSContext* cx, JSFunction* fun, JSScript* script)
 {
-    JSAutoByteString funNameBytes;
+    UniqueChars funNameBytes;
     JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), probes::nullName,
                               FunctionName(cx, fun, &funNameBytes));
 }
 
 void
 probes::DTraceExitJSFun(JSContext* cx, JSFunction* fun, JSScript* script)
 {
-    JSAutoByteString funNameBytes;
+    UniqueChars funNameBytes;
     JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), probes::nullName,
                                FunctionName(cx, fun, &funNameBytes));
 }
 #endif
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1815,25 +1815,24 @@ SavedStacks::MetadataBuilder::build(JSCo
     return frame;
 }
 
 const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
 
 /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsSystem;
 /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem;
 
-UTF8CharsZ
+UniqueChars
 BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack)
 {
     RootedString stackStr(cx);
     if (!JS::BuildStackString(cx, principals, stack, &stackStr))
-        return UTF8CharsZ();
+        return nullptr;
 
-    char* chars = JS_EncodeStringToUTF8(cx, stackStr);
-    return UTF8CharsZ(chars, strlen(chars));
+    return JS_EncodeStringToUTF8(cx, stackStr);
 }
 
 uint32_t
 FixupColumnForDisplay(uint32_t column)
 {
     // As described in WasmFrameIter::computeLine(), for wasm frames, the
     // function index is returned as the column with the high bit set. In paths
     // that format error stacks into strings, this information can be used to
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -315,17 +315,17 @@ struct MutableWrappedPtrOperations<Saved
     void setColumn(uint32_t v) { loc().column = v; }
 
   private:
     SavedStacks::LocationValue& loc() {
         return static_cast<Wrapper*>(this)->get();
     }
 };
 
-UTF8CharsZ
+JS::UniqueChars
 BuildUTF8StackString(JSContext* cx, JSPrincipals* principals, HandleObject stack);
 
 uint32_t
 FixupColumnForDisplay(uint32_t column);
 
 } /* namespace js */
 
 #endif /* vm_SavedStacks_h */
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -9,17 +9,16 @@
 #include "mozilla/ScopeExit.h"
 
 #include <memory>
 #include <new>
 
 #include "builtin/ModuleObject.h"
 #include "gc/Allocator.h"
 #include "gc/FreeOp.h"
-#include "js/AutoByteString.h"
 #include "util/StringBuffer.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/JSScript.h"
 #include "wasm/WasmInstance.h"
 
 #include "gc/ObjectKind-inl.h"
 #include "vm/Shape-inl.h"
 
@@ -1515,20 +1514,20 @@ PositionalFormalParameterIter::Positiona
     settle();
 }
 
 void
 js::DumpBindings(JSContext* cx, Scope* scopeArg)
 {
     RootedScope scope(cx, scopeArg);
     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (!AtomToPrintableString(cx, bi.name(), &bytes))
             return;
-        fprintf(stderr, "%s %s ", BindingKindString(bi.kind()), bytes.ptr());
+        fprintf(stderr, "%s %s ", BindingKindString(bi.kind()), bytes.get());
         switch (bi.location().kind()) {
           case BindingLocation::Kind::Global:
             if (bi.isTopLevelFunction())
                 fprintf(stderr, "global function\n");
             else
                 fprintf(stderr, "global\n");
             break;
           case BindingLocation::Kind::Argument:
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -33,17 +33,16 @@
 #include "builtin/String.h"
 #include "builtin/TypedObject.h"
 #include "builtin/WeakMapObject.h"
 #include "gc/HashUtil.h"
 #include "gc/Marking.h"
 #include "gc/Policy.h"
 #include "jit/AtomicOperations.h"
 #include "jit/InlinableNatives.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/Date.h"
 #include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Compression.h"
@@ -288,38 +287,38 @@ ThrowErrorWithType(JSContext* cx, JSExnT
     uint32_t errorNumber = args[0].toInt32();
 
 #ifdef DEBUG
     const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
     MOZ_ASSERT(efs->argCount == args.length() - 1);
     MOZ_ASSERT(efs->exnType == type, "error-throwing intrinsic and error number are inconsistent");
 #endif
 
-    JSAutoByteString errorArgs[3];
+    UniqueChars errorArgs[3];
     for (unsigned i = 1; i < 4 && i < args.length(); i++) {
         RootedValue val(cx, args[i]);
         if (val.isInt32()) {
             JSString* str = ToString<CanGC>(cx, val);
             if (!str)
                 return;
-            errorArgs[i - 1].encodeLatin1(cx, str);
+            errorArgs[i - 1] = JS_EncodeString(cx, str);
         } else if (val.isString()) {
-            errorArgs[i - 1].encodeLatin1(cx, val.toString());
+            errorArgs[i - 1] = JS_EncodeString(cx, val.toString());
         } else {
             UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
             if (!bytes)
                 return;
-            errorArgs[i - 1].initBytes(std::move(bytes));
+            errorArgs[i - 1] = std::move(bytes);
         }
         if (!errorArgs[i - 1])
             return;
     }
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber,
-                               errorArgs[0].ptr(), errorArgs[1].ptr(), errorArgs[2].ptr());
+                               errorArgs[0].get(), errorArgs[1].get(), errorArgs[2].get());
 }
 
 static bool
 intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() >= 1);
 
@@ -1864,17 +1863,17 @@ js::ReportIncompatibleSelfHostedMethod(J
     // like array.sort(somethingSelfHosted), where we want to report the error
     // in the somethingSelfHosted, not in the sort() call.
     ScriptFrameIter iter(cx);
     MOZ_ASSERT(iter.isFunctionFrame());
 
     while (!iter.done()) {
         MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic() &&
                    !iter.callee(cx)->isBoundFunction());
-        JSAutoByteString funNameBytes;
+        UniqueChars funNameBytes;
         const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
         if (!funName)
             return false;
         if (strcmp(funName, "IsTypedArrayEnsuringArrayBuffer") != 0) {
             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
                                        funName, "method", InformalValueTypeName(args.thisv()));
             return false;
         }
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -15,17 +15,17 @@
 #include "mozilla/RangedPtr.h"
 #include "mozilla/TextUtils.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Unused.h"
 
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #include "gc/Nursery.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 #include "js/UbiNode.h"
 #include "util/StringBuffer.h"
 #include "vm/GeckoProfiler.h"
 
 #include "vm/GeckoProfiler-inl.h"
 #include "vm/JSContext-inl.h"
 #include "vm/JSObject-inl.h"
@@ -2058,45 +2058,47 @@ js::EncodeLatin1(JSContext* cx, JSString
         return nullptr;
 
     mozilla::PodCopy(buf, linear->latin1Chars(nogc), len);
     buf[len] = '\0';
     return UniqueChars(reinterpret_cast<char*>(buf));
 }
 
 const char*
-js::ValueToPrintableLatin1(JSContext* cx, const Value& vArg, JSAutoByteString* bytes,
+js::ValueToPrintableLatin1(JSContext* cx, const Value& vArg, UniqueChars* bytes,
                            bool asSource)
 {
     RootedValue v(cx, vArg);
     JSString* str;
     if (asSource)
         str = ValueToSource(cx, v);
     else
         str = ToString<CanGC>(cx, v);
     if (!str)
         return nullptr;
     str = QuoteString(cx, str, 0);
     if (!str)
         return nullptr;
-    return bytes->encodeLatin1(cx, str);
+    *bytes = JS_EncodeString(cx, str);
+    return bytes->get();
 }
 
 const char*
-js::ValueToPrintableUTF8(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
+js::ValueToPrintableUTF8(JSContext* cx, const Value& vArg, UniqueChars* bytes, bool asSource)
 {
     RootedValue v(cx, vArg);
     JSString* str;
     if (asSource)
         str = ValueToSource(cx, v);
     else
         str = ToString<CanGC>(cx, v);
     if (!str)
         return nullptr;
-    return bytes->encodeUtf8(cx, RootedString(cx, str));
+    *bytes = JS_EncodeStringToUTF8(cx, RootedString(cx, str));
+    return bytes->get();
 }
 
 template <AllowGC allowGC>
 JSString*
 js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
 {
     /* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
     MOZ_ASSERT(!arg.isString());
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -21,17 +21,16 @@
 #include "gc/Nursery.h"
 #include "gc/Rooting.h"
 #include "js/CharacterEncoding.h"
 #include "js/RootingAPI.h"
 #include "js/UniquePtr.h"
 #include "util/Text.h"
 #include "vm/Printer.h"
 
-class JSAutoByteString;
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSInlineString;
 class JSRope;
 
 namespace JS {
 
@@ -1682,24 +1681,24 @@ EncodeLatin1(JSContext* cx, JSString* st
  * Convert a value to a printable C string.
  *
  * As the function name implies, any characters in a converted printable string will be Latin1
  * characters. If there are any non-Latin1 characters in the original value, then those characters
  * will be changed to Unicode escape sequences(I.e. \udddd, dddd are 4 hex digits) in the printable
  * string.
  */
 extern const char*
-ValueToPrintableLatin1(JSContext* cx, const Value&, JSAutoByteString* bytes,
+ValueToPrintableLatin1(JSContext* cx, const Value&, UniqueChars* bytes,
                        bool asSource = false);
 
 /*
  * Convert a value to a printable C string encoded in UTF-8.
  */
 extern const char*
-ValueToPrintableUTF8(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
+ValueToPrintableUTF8(JSContext* cx, const Value&, UniqueChars* bytes, bool asSource = false);
 
 /*
  * Convert a non-string value to a string, returning null after reporting an
  * error, otherwise returning a new string reference.
  */
 template <AllowGC allowGC>
 extern JSString*
 ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
--- a/js/src/vm/UbiNodeCensus.cpp
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "js/UbiNodeCensus.h"
 
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/StableStringChars.h"
 #include "util/Text.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
@@ -1260,22 +1260,22 @@ ParseBreakdown(JSContext* cx, HandleValu
         return CountTypePtr(cx->new_<ByFilename>(std::move(thenType), std::move(noFilenameType)));
     }
 
     // We didn't recognize the breakdown type; complain.
     RootedString bySource(cx, ValueToSource(cx, byValue));
     if (!bySource)
         return nullptr;
 
-    JSAutoByteString byBytes(cx, bySource);
+    UniqueChars byBytes = JS_EncodeString(cx, bySource);
     if (!byBytes)
         return nullptr;
 
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_CENSUS_BREAKDOWN,
-                               byBytes.ptr());
+                               byBytes.get());
     return nullptr;
 }
 
 // Get the default census breakdown:
 //
 // { by: "coarseType",
 //   objects: { by: "objectClass" },
 //   other:   { by: "internalType" },
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -27,17 +27,16 @@
 #include <new>
 
 #include "jsmath.h"
 #include "jsutil.h"
 
 #include "builtin/String.h"
 #include "frontend/Parser.h"
 #include "gc/Policy.h"
-#include "js/AutoByteString.h"
 #include "js/MemoryMetrics.h"
 #include "js/Printf.h"
 #include "js/SourceBufferHolder.h"
 #include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/ErrorReporting.h"
@@ -2012,19 +2011,19 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED Modu
         failfVAOffset(pn->pn_pos.begin, fmt, ap);
         va_end(ap);
         return false;
     }
 
     bool failNameOffset(uint32_t offset, const char* fmt, PropertyName* name) {
         // This function is invoked without the caller properly rooting its locals.
         gc::AutoSuppressGC suppress(cx_);
-        JSAutoByteString bytes;
+        UniqueChars bytes;
         if (AtomToPrintableString(cx_, name, &bytes))
-            failfOffset(offset, fmt, bytes.ptr());
+            failfOffset(offset, fmt, bytes.get());
         return false;
     }
 
     bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
         return failNameOffset(pn->pn_pos.begin, fmt, name);
     }
 
     bool failOverRecursed() {
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -12,17 +12,17 @@
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 #include "jsapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/Printf.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsExceptionHandler.h"
 #include "nsIComponentManager.h"
 #include "mozilla/Module.h"
 #include "nsIFile.h"
@@ -101,32 +101,32 @@ Dump(JSContext* cx, unsigned argc, Value
 
     if (args.length() == 0)
         return true;
 
     RootedString str(cx, JS::ToString(cx, args[0]));
     if (!str)
         return false;
 
-    JSAutoByteString utf8str;
-    if (!utf8str.encodeUtf8(cx, str))
+    JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
+    if (!utf8str)
         return false;
 
 #ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
+    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
 #endif
 #ifdef XP_WIN
     if (IsDebuggerPresent()) {
         nsAutoJSString wstr;
         if (!wstr.init(cx, str))
             return false;
         OutputDebugStringW(wstr.get());
     }
 #endif
-    fputs(utf8str.ptr(), stdout);
+    fputs(utf8str.get(), stdout);
     fflush(stdout);
     return true;
 }
 
 static bool
 Debug(JSContext* cx, unsigned argc, Value* vp)
 {
 #ifdef DEBUG
@@ -1236,43 +1236,43 @@ mozJSComponentLoader::ExtractExports(JSC
             !value.isString() ||
             !JS_ValueToId(cx, value, &symbolId)) {
             return ReportOnCallerUTF8(cxhelper, ERROR_ARRAY_ELEMENT, aInfo, i);
         }
 
         symbolHolder = ResolveModuleObjectPropertyById(cx, aMod->obj, symbolId);
         if (!symbolHolder ||
             !JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) {
-            JSAutoByteString bytes;
             RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
-            if (!bytes.encodeUtf8(cx, symbolStr))
+            JS::UniqueChars bytes = JS_EncodeStringToUTF8(cx, symbolStr);
+            if (!bytes)
                 return NS_ERROR_FAILURE;
             return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
-                                      aInfo, bytes.ptr());
+                                      aInfo, bytes.get());
         }
 
         if (value.isUndefined()) {
             missing = true;
         }
 
         if (!JS_SetPropertyById(cx, aExports, symbolId, value)) {
-            JSAutoByteString bytes;
             RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
-            if (!bytes.encodeUtf8(cx, symbolStr))
+            JS::UniqueChars bytes = JS_EncodeStringToUTF8(cx, symbolStr);
+            if (!bytes)
                 return NS_ERROR_FAILURE;
             return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
-                                      aInfo, bytes.ptr());
+                                      aInfo, bytes.get());
         }
 #ifdef DEBUG
         if (i == 0) {
             logBuffer.AssignLiteral("Installing symbols [ ");
         }
-        JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId));
+        JS::UniqueChars bytes = JS_EncodeString(cx, JSID_TO_STRING(symbolId));
         if (!!bytes)
-            logBuffer.Append(bytes.ptr());
+            logBuffer.Append(bytes.get());
         logBuffer.Append(' ');
         if (i == symbolCount - 1) {
             nsCString location;
             MOZ_TRY(aInfo.GetLocation(location));
             LOG(("%s] from %s\n", logBuffer.get(), location.get()));
         }
 #endif
     }
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * The Components.Sandbox object.
  */
 
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/Proxy.h"
 #include "js/SourceBufferHolder.h"
 #include "js/StructuredClone.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsIException.h" // for nsIStackFrame
 #include "nsIScriptContext.h"
@@ -135,18 +135,18 @@ SandboxDump(JSContext* cx, unsigned argc
 
     if (args.length() == 0)
         return true;
 
     RootedString str(cx, ToString(cx, args[0]));
     if (!str)
         return false;
 
-    JSAutoByteString utf8str;
-    char* cstr = utf8str.encodeUtf8(cx, str);
+    JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
+    char* cstr = utf8str.get();
     if (!cstr)
         return false;
 
 #if defined(XP_MACOSX)
     // Be nice and convert all \r to \n.
     char* c = cstr;
     char* cEnd = cstr + strlen(cstr);
     while (c < cEnd) {
@@ -850,79 +850,79 @@ xpc::GlobalProperties::Parse(JSContext* 
         RootedValue nameValue(cx);
         ok = JS_GetElement(cx, obj, i, &nameValue);
         NS_ENSURE_TRUE(ok, false);
         if (!nameValue.isString()) {
             JS_ReportErrorASCII(cx, "Property names must be strings");
             return false;
         }
         RootedString nameStr(cx, nameValue.toString());
-        JSAutoByteString name;
-        if (!name.encodeUtf8(cx, nameStr))
+        JS::UniqueChars name = JS_EncodeStringToUTF8(cx, nameStr);
+        if (!name)
             return false;
-        if (!strcmp(name.ptr(), "Blob")) {
+        if (!strcmp(name.get(), "Blob")) {
             Blob = true;
-        } else if (!strcmp(name.ptr(), "ChromeUtils")) {
+        } else if (!strcmp(name.get(), "ChromeUtils")) {
             ChromeUtils = true;
-        } else if (!strcmp(name.ptr(), "CSS")) {
+        } else if (!strcmp(name.get(), "CSS")) {
             CSS = true;
-        } else if (!strcmp(name.ptr(), "CSSRule")) {
+        } else if (!strcmp(name.get(), "CSSRule")) {
             CSSRule = true;
-        } else if (!strcmp(name.ptr(), "Directory")) {
+        } else if (!strcmp(name.get(), "Directory")) {
             Directory = true;
-        } else if (!strcmp(name.ptr(), "DOMParser")) {
+        } else if (!strcmp(name.get(), "DOMParser")) {
             DOMParser = true;
-        } else if (!strcmp(name.ptr(), "Element")) {
+        } else if (!strcmp(name.get(), "Element")) {
             Element = true;
-        } else if (!strcmp(name.ptr(), "Event")) {
+        } else if (!strcmp(name.get(), "Event")) {
             Event = true;
-        } else if (!strcmp(name.ptr(), "File")) {
+        } else if (!strcmp(name.get(), "File")) {
             File = true;
-        } else if (!strcmp(name.ptr(), "FileReader")) {
+        } else if (!strcmp(name.get(), "FileReader")) {
             FileReader = true;
-        } else if (!strcmp(name.ptr(), "FormData")) {
+        } else if (!strcmp(name.get(), "FormData")) {
             FormData = true;
-        } else if (!strcmp(name.ptr(), "InspectorUtils")) {
+        } else if (!strcmp(name.get(), "InspectorUtils")) {
             InspectorUtils = true;
-        } else if (!strcmp(name.ptr(), "MessageChannel")) {
+        } else if (!strcmp(name.get(), "MessageChannel")) {
             MessageChannel = true;
-        } else if (!strcmp(name.ptr(), "Node")) {
+        } else if (!strcmp(name.get(), "Node")) {
             Node = true;
-        } else if (!strcmp(name.ptr(), "NodeFilter")) {
+        } else if (!strcmp(name.get(), "NodeFilter")) {
             NodeFilter = true;
-        } else if (!strcmp(name.ptr(), "TextDecoder")) {
+        } else if (!strcmp(name.get(), "TextDecoder")) {
             TextDecoder = true;
-        } else if (!strcmp(name.ptr(), "TextEncoder")) {
+        } else if (!strcmp(name.get(), "TextEncoder")) {
             TextEncoder = true;
-        } else if (!strcmp(name.ptr(), "URL")) {
+        } else if (!strcmp(name.get(), "URL")) {
             URL = true;
-        } else if (!strcmp(name.ptr(), "URLSearchParams")) {
+        } else if (!strcmp(name.get(), "URLSearchParams")) {
             URLSearchParams = true;
-        } else if (!strcmp(name.ptr(), "XMLHttpRequest")) {
+        } else if (!strcmp(name.get(), "XMLHttpRequest")) {
             XMLHttpRequest = true;
-        } else if (!strcmp(name.ptr(), "XMLSerializer")) {
+        } else if (!strcmp(name.get(), "XMLSerializer")) {
             XMLSerializer = true;
-        } else if (!strcmp(name.ptr(), "atob")) {
+        } else if (!strcmp(name.get(), "atob")) {
             atob = true;
-        } else if (!strcmp(name.ptr(), "btoa")) {
+        } else if (!strcmp(name.get(), "btoa")) {
             btoa = true;
-        } else if (!strcmp(name.ptr(), "caches")) {
+        } else if (!strcmp(name.get(), "caches")) {
             caches = true;
-        } else if (!strcmp(name.ptr(), "crypto")) {
+        } else if (!strcmp(name.get(), "crypto")) {
             crypto = true;
-        } else if (!strcmp(name.ptr(), "fetch")) {
+        } else if (!strcmp(name.get(), "fetch")) {
             fetch = true;
-        } else if (!strcmp(name.ptr(), "indexedDB")) {
+        } else if (!strcmp(name.get(), "indexedDB")) {
             indexedDB = true;
 #ifdef MOZ_WEBRTC
-        } else if (!strcmp(name.ptr(), "rtcIdentityProvider")) {
+        } else if (!strcmp(name.get(), "rtcIdentityProvider")) {
             rtcIdentityProvider = true;
 #endif
         } else {
-            JS_ReportErrorUTF8(cx, "Unknown property name: %s", name.ptr());
+            JS_ReportErrorUTF8(cx, "Unknown property name: %s", name.get());
             return false;
         }
     }
     return true;
 }
 
 bool
 xpc::GlobalProperties::Define(JSContext* cx, JS::HandleObject obj)
@@ -1535,20 +1535,19 @@ OptionsBase::ParseString(const char* nam
     if (!found)
         return true;
 
     if (!value.isString()) {
         JS_ReportErrorASCII(mCx, "Expected a string value for property %s", name);
         return false;
     }
 
-    char* tmp = JS_EncodeString(mCx, value.toString());
+    JS::UniqueChars tmp = JS_EncodeString(mCx, value.toString());
     NS_ENSURE_TRUE(tmp, false);
-    prop.Assign(tmp, strlen(tmp));
-    js_free(tmp);
+    prop.Assign(tmp.get(), strlen(tmp.get()));
     return true;
 }
 
 /*
  * Helper that tries to get a string property from the options object.
  */
 bool
 OptionsBase::ParseString(const char* name, nsString& prop)
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -10,17 +10,17 @@
 #include "xpc_make_class.h"
 #include "XPCJSWeakReference.h"
 #include "WrapperFactory.h"
 #include "nsJSUtils.h"
 #include "mozJSComponentLoader.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/SavedFrameAPI.h"
 #include "js/StructuredClone.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/Preferences.h"
 #include "nsJSEnvironment.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ResultExtensions.h"
@@ -241,22 +241,22 @@ nsXPCComponents_Interfaces::Resolve(nsIX
                                     bool* _retval)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
 
     if (!JSID_IS_STRING(id))
         return NS_OK;
 
-    JSAutoByteString name;
     RootedString str(cx, JSID_TO_STRING(id));
+    JS::UniqueChars name = JS_EncodeString(cx, str);
 
     // we only allow interfaces by name here
-    if (name.encodeLatin1(cx, str) && name.ptr()[0] != '{') {
-        const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name.ptr());
+    if (name && name[0] != '{') {
+        const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name.get());
         if (!info)
             return NS_OK;
 
         nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info);
 
         if (nsid) {
             nsXPConnect* xpc = nsXPConnect::XPConnect();
             RootedObject idobj(cx);
@@ -426,20 +426,20 @@ nsXPCComponents_InterfacesByID::Resolve(
 
     if (!JSID_IS_STRING(id))
         return NS_OK;
 
     RootedString str(cx, JSID_TO_STRING(id));
     if (38 != JS_GetStringLength(str))
         return NS_OK;
 
-    JSAutoByteString utf8str;
-    if (utf8str.encodeUtf8(cx, str)) {
+    JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
+    if (utf8str) {
         nsID iid;
-        if (!iid.Parse(utf8str.ptr()))
+        if (!iid.Parse(utf8str.get()))
             return NS_OK;
 
         const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(iid);
         if (!info)
             return NS_OK;
 
         nsCOMPtr<nsIJSIID> nsid = nsJSIID::NewID(info);
 
@@ -618,21 +618,23 @@ nsXPCComponents_Classes::Resolve(nsIXPCo
                                  JSContext* cx, JSObject* objArg,
                                  jsid idArg, bool* resolvedp,
                                  bool* _retval)
 
 {
     RootedId id(cx, idArg);
     RootedObject obj(cx, objArg);
 
-    JSAutoByteString name;
-    if (JSID_IS_STRING(id) &&
-        name.encodeLatin1(cx, JSID_TO_STRING(id)) &&
-        name.ptr()[0] != '{') { // we only allow contractids here
-        nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr());
+    if (!JSID_IS_STRING(id))
+        return NS_OK;
+
+    JS::UniqueChars name = JS_EncodeString(cx, JSID_TO_STRING(id));
+    if (name &&
+        name[0] != '{') { // we only allow contractids here
+        nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.get());
         if (nsid) {
             nsXPConnect* xpc = nsXPConnect::XPConnect();
             RootedObject idobj(cx);
             if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                              static_cast<nsIJSCID*>(nsid),
                                              NS_GET_IID(nsIJSCID),
                                              idobj.address()))) {
                 if (idobj) {
@@ -827,22 +829,22 @@ nsXPCComponents_ClassesByID::Resolve(nsI
                                      bool* _retval)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
 
     if (!JSID_IS_STRING(id))
         return NS_OK;
 
-    JSAutoByteString name;
     RootedString str(cx, JSID_TO_STRING(id));
-    if (name.encodeLatin1(cx, str) && name.ptr()[0] == '{' &&
-        IsRegisteredCLSID(name.ptr())) // we only allow canonical CLSIDs here
+    JS::UniqueChars name = JS_EncodeString(cx, str);
+    if (name && name[0] == '{' &&
+        IsRegisteredCLSID(name.get())) // we only allow canonical CLSIDs here
     {
-        nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.ptr());
+        nsCOMPtr<nsIJSCID> nsid = nsJSCID::NewID(name.get());
         if (nsid) {
             nsXPConnect* xpc = nsXPConnect::XPConnect();
             RootedObject idobj(cx);
             if (NS_SUCCEEDED(xpc->WrapNative(cx, obj,
                                              static_cast<nsIJSCID*>(nsid),
                                              NS_GET_IID(nsIJSCID),
                                              idobj.address()))) {
                 if (idobj) {
@@ -993,24 +995,26 @@ nsXPCComponents_Results::NewEnumerate(ns
 NS_IMETHODIMP
 nsXPCComponents_Results::Resolve(nsIXPConnectWrappedNative* wrapper,
                                  JSContext* cx, JSObject* objArg,
                                  jsid idArg, bool* resolvedp,
                                  bool* _retval)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
-    JSAutoByteString name;
-
-    if (JSID_IS_STRING(id) && name.encodeLatin1(cx, JSID_TO_STRING(id))) {
+    if (!JSID_IS_STRING(id))
+        return NS_OK;
+
+    JS::UniqueChars name = JS_EncodeString(cx, JSID_TO_STRING(id));
+    if (name) {
         const char* rv_name;
         const void* iter = nullptr;
         nsresult rv;
         while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) {
-            if (!strcmp(name.ptr(), rv_name)) {
+            if (!strcmp(name.get(), rv_name)) {
                 *resolvedp = true;
                 if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv,
                                            JSPROP_ENUMERATE |
                                            JSPROP_READONLY |
                                            JSPROP_PERMANENT |
                                            JSPROP_RESOLVING)) {
                     return NS_ERROR_UNEXPECTED;
                 }
@@ -1156,25 +1160,27 @@ nsXPCComponents_ID::CallOrConstruct(nsIX
     if (NS_FAILED(nsXPConnect::SecurityManager()->CanCreateInstance(cx, nsJSID::GetCID()))) {
         // the security manager vetoed. It should have set an exception.
         *_retval = false;
         return NS_OK;
     }
 
     // convert the first argument into a string and see if it looks like an id
 
-    JSString* jsstr;
-    JSAutoByteString bytes;
+    JSString* jsstr = ToString(cx, args[0]);
+    if (!jsstr)
+        return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
+
+    JS::UniqueChars bytes = JS_EncodeString(cx, jsstr);
+    if (!bytes)
+        return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
+
     nsID id;
-
-    if (!(jsstr = ToString(cx, args[0])) ||
-        !bytes.encodeLatin1(cx, jsstr) ||
-        !id.Parse(bytes.ptr())) {
+    if (!id.Parse(bytes.get()))
         return ThrowAndFail(NS_ERROR_XPC_BAD_ID_STRING, cx, _retval);
-    }
 
     // make the new object and return it.
 
     JSObject* newobj = xpc_NewIDObject(cx, obj, id);
     if (!newobj)
         return NS_ERROR_UNEXPECTED;
 
     args.rval().setObject(*newobj);
@@ -1377,17 +1383,18 @@ struct MOZ_STACK_CLASS ExceptionArgParse
     /*
      * Parsing helpers.
      */
 
     bool parseMessage(HandleValue v) {
         JSString* str = ToString(cx, v);
         if (!str)
            return false;
-        eMsg = messageBytes.encodeLatin1(cx, str);
+        messageBytes = JS_EncodeString(cx, str);
+        eMsg = messageBytes.get();
         return !!eMsg;
     }
 
     bool parseResult(HandleValue v) {
         return JS::ToUint32(cx, v, (uint32_t*) &eResult);
     }
 
     bool parseStack(HandleValue v) {
@@ -1448,17 +1455,17 @@ struct MOZ_STACK_CLASS ExceptionArgParse
         return JS_GetProperty(cx, obj, name, rv);
     }
 
     /*
      * Internal data members.
      */
 
     // If there's a non-default exception string, hold onto the allocated bytes.
-    JSAutoByteString messageBytes;
+    JS::UniqueChars messageBytes;
 
     // Various bits and pieces that are helpful to have around.
     JSContext* cx;
     nsXPConnect* xpc;
 };
 
 // static
 nsresult
@@ -1866,22 +1873,27 @@ nsXPCComponents_Constructor::CallOrConst
         *_retval = false;
         return NS_OK;
     }
 
     // initialization params for the Constructor object we will create
     nsCOMPtr<nsIJSCID> cClassID;
     nsCOMPtr<nsIJSIID> cInterfaceID;
     const char*        cInitializer = nullptr;
-    JSAutoByteString  cInitializerBytes;
+    JS::UniqueChars cInitializerBytes;
 
     if (args.length() >= 3) {
         // args[2] is an initializer function or property name
         RootedString str(cx, ToString(cx, args[2]));
-        if (!str || !(cInitializer = cInitializerBytes.encodeLatin1(cx, str)))
+        if (!str)
+            return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
+
+        cInitializerBytes = JS_EncodeString(cx, str);
+        cInitializer = cInitializerBytes.get();
+        if (!cInitializer)
             return ThrowAndFail(NS_ERROR_XPC_BAD_CONVERT_JS, cx, _retval);
     }
 
     if (args.length() >= 2) {
         // args[1] is an iid name string
         // XXXjband support passing "Components.interfaces.foo"?
 
         nsCOMPtr<nsIXPCComponents_Interfaces> ifaces;
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -16,17 +16,16 @@
 #include "nsQueryObject.h"
 #include "nsScriptError.h"
 #include "WrapperFactory.h"
 
 #include "nsWrapperCacheInlines.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
 #include "js/CharacterEncoding.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/PrimitiveConversions.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 
@@ -1328,41 +1327,41 @@ XPCConvert::JSValToXPCException(MutableH
                                       exceptn, nullptr, nullptr);
         } else {
             // It is a JSObject, but not a wrapped native...
 
             // If it is an engine Error with an error report then let's
             // extract the report and build an xpcexception from that
             const JSErrorReport* report;
             if (nullptr != (report = JS_ErrorFromException(cx, obj))) {
-                JSAutoByteString toStringResult;
+                JS::UniqueChars toStringResult;
                 RootedString str(cx, ToString(cx, s));
                 if (str)
-                    toStringResult.encodeUtf8(cx, str);
-                return JSErrorToXPCException(toStringResult.ptr(), ifaceName,
+                    toStringResult = JS_EncodeStringToUTF8(cx, str);
+                return JSErrorToXPCException(toStringResult.get(), ifaceName,
                                              methodName, report, exceptn);
             }
 
             // XXX we should do a check against 'js_ErrorClass' here and
             // do the right thing - even though it has no JSErrorReport,
             // The fact that it is a JSError exceptions means we can extract
             // particular info and our 'result' should reflect that.
 
             // otherwise we'll just try to convert it to a string
 
             JSString* str = ToString(cx, s);
             if (!str)
                 return NS_ERROR_FAILURE;
 
-            JSAutoByteString strBytes(cx, str);
+            JS::UniqueChars strBytes = JS_EncodeString(cx, str);
             if (!strBytes)
                 return NS_ERROR_FAILURE;
 
             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
-                                      strBytes.ptr(), ifaceName, methodName,
+                                      strBytes.get(), ifaceName, methodName,
                                       nullptr, exceptn, cx, s.address());
         }
     }
 
     if (s.isUndefined() || s.isNull()) {
         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
                                   nullptr, ifaceName, methodName, nullptr,
                                   exceptn, cx, s.address());
@@ -1415,20 +1414,20 @@ XPCConvert::JSValToXPCException(MutableH
         }
     }
 
     // otherwise we'll just try to convert it to a string
     // Note: e.g., bools get converted to JSStrings by this code.
 
     JSString* str = ToString(cx, s);
     if (str) {
-        JSAutoByteString strBytes(cx, str);
+        JS::UniqueChars strBytes = JS_EncodeString(cx, str);
         if (!!strBytes) {
             return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
-                                      strBytes.ptr(), ifaceName, methodName,
+                                      strBytes.get(), ifaceName, methodName,
                                       nullptr, exceptn, cx, s.address());
         }
     }
     return NS_ERROR_FAILURE;
 }
 
 /***************************************************************************/
 
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -2,17 +2,17 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
 /* 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 "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/Printf.h"
 #include "mozilla/ChaosMode.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Preferences.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsExceptionHandler.h"
@@ -245,18 +245,18 @@ ReadLine(JSContext* cx, unsigned argc, V
         str = JS::ToString(cx, args[0]);
         if (!str)
             return false;
     } else {
         str = JS_GetEmptyString(cx);
     }
 
     /* Get a line from the infile */
-    JSAutoByteString strBytes(cx, str);
-    if (!strBytes || !GetLine(cx, buf, gInFile, strBytes.ptr()))
+    JS::UniqueChars strBytes = JS_EncodeString(cx, str);
+    if (!strBytes || !GetLine(cx, buf, gInFile, strBytes.get()))
         return false;
 
     /* Strip newline character added by GetLine() */
     unsigned int buflen = strlen(buf);
     if (buflen == 0) {
         if (feof(gInFile)) {
             args.rval().setNull();
             return true;
@@ -283,23 +283,23 @@ Print(JSContext* cx, unsigned argc, Valu
     RootedString str(cx);
     nsAutoCString utf8output;
 
     for (unsigned i = 0; i < args.length(); i++) {
         str = ToString(cx, args[i]);
         if (!str)
             return false;
 
-        JSAutoByteString utf8str;
-        if (!utf8str.encodeUtf8(cx, str))
+        JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
+        if (!utf8str)
             return false;
 
         if (i)
             utf8output.Append(' ');
-        utf8output.Append(utf8str.ptr(), utf8str.length());
+        utf8output.Append(utf8str.get(), strlen(utf8str.get()));
     }
     utf8output.Append('\n');
     fputs(utf8output.get(), gOutFile);
     fflush(gOutFile);
     return true;
 }
 
 static bool
@@ -310,32 +310,32 @@ Dump(JSContext* cx, unsigned argc, Value
 
     if (!args.length())
          return true;
 
     RootedString str(cx, ToString(cx, args[0]));
     if (!str)
         return false;
 
-    JSAutoByteString utf8str;
-    if (!utf8str.encodeUtf8(cx, str))
+    JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
+    if (!utf8str)
         return false;
 
 #ifdef ANDROID
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
+    __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
 #endif
 #ifdef XP_WIN
     if (IsDebuggerPresent()) {
         nsAutoJSString wstr;
         if (!wstr.init(cx, str))
             return false;
         OutputDebugStringW(wstr.get());
     }
 #endif
-    fputs(utf8str.ptr(), gOutFile);
+    fputs(utf8str.get(), gOutFile);
     fflush(gOutFile);
     return true;
 }
 
 static bool
 Load(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -348,31 +348,31 @@ Load(JSContext* cx, unsigned argc, Value
         return false;
     }
 
     RootedString str(cx);
     for (unsigned i = 0; i < args.length(); i++) {
         str = ToString(cx, args[i]);
         if (!str)
             return false;
-        JSAutoByteString filename(cx, str);
+        JS::UniqueChars filename = JS_EncodeString(cx, str);
         if (!filename)
             return false;
-        FILE* file = fopen(filename.ptr(), "r");
+        FILE* file = fopen(filename.get(), "r");
         if (!file) {
-            filename.clear();
-            if (!filename.encodeUtf8(cx, str))
+            filename = JS_EncodeStringToUTF8(cx, str);
+            if (!filename)
                 return false;
             JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading",
-                               filename.ptr());
+                               filename.get());
             return false;
         }
         JS::CompileOptions options(cx);
         options.setUTF8(true)
-               .setFileAndLine(filename.ptr(), 1)
+               .setFileAndLine(filename.get(), 1)
                .setIsRunOnce(true);
         JS::Rooted<JSScript*> script(cx);
         JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
         JS::Compile(cx, options, file, &script);
         fclose(file);
         if (!script)
             return false;
 
@@ -474,35 +474,35 @@ SendCommand(JSContext* cx, unsigned argc
 
 static bool
 Options(JSContext* cx, unsigned argc, Value* vp)
 {
     JS::CallArgs args = CallArgsFromVp(argc, vp);
     ContextOptions oldContextOptions = ContextOptionsRef(cx);
 
     RootedString str(cx);
-    JSAutoByteString opt;
+    JS::UniqueChars opt;
     for (unsigned i = 0; i < args.length(); ++i) {
         str = ToString(cx, args[i]);
         if (!str)
             return false;
 
-        opt.clear();
-        if (!opt.encodeUtf8(cx, str))
+        opt = JS_EncodeStringToUTF8(cx, str);
+        if (!opt)
             return false;
 
-        if (strcmp(opt.ptr(), "strict") == 0)
+        if (strcmp(opt.get(), "strict") == 0)
             ContextOptionsRef(cx).toggleExtraWarnings();
-        else if (strcmp(opt.ptr(), "werror") == 0)
+        else if (strcmp(opt.get(), "werror") == 0)
             ContextOptionsRef(cx).toggleWerror();
-        else if (strcmp(opt.ptr(), "strict_mode") == 0)
+        else if (strcmp(opt.get(), "strict_mode") == 0)
             ContextOptionsRef(cx).toggleStrictMode();
         else {
             JS_ReportErrorUTF8(cx, "unknown option name '%s'. The valid names are "
-                               "strict, werror, and strict_mode.", opt.ptr());
+                               "strict, werror, and strict_mode.", opt.get());
             return false;
         }
     }
 
     UniqueChars names;
     if (oldContextOptions.extraWarnings()) {
         names = JS_sprintf_append(std::move(names), "%s", "strict");
         if (!names) {
@@ -721,21 +721,21 @@ ProcessLine(AutoJSAPI& jsapi, const char
     if (!JS_ExecuteScript(cx, script, &result))
         return false;
 
     if (result.isUndefined())
         return true;
     RootedString str(cx);
     if (!(str = ToString(cx, result)))
         return false;
-    JSAutoByteString bytes;
-    if (!bytes.encodeLatin1(cx, str))
+    JS::UniqueChars bytes = JS_EncodeString(cx, str);
+    if (!bytes)
         return false;
 
-    fprintf(gOutFile, "%s\n", bytes.ptr());
+    fprintf(gOutFile, "%s\n", bytes.get());
     return true;
 }
 
 static bool
 ProcessFile(AutoJSAPI& jsapi, const char* filename, FILE* file, bool forceTTY)
 {
     JSContext* cx = jsapi.cx();
     JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
--- a/js/xpconnect/src/XPCThrower.cpp
+++ b/js/xpconnect/src/XPCThrower.cpp
@@ -3,17 +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/. */
 
 /* Code for throwing errors into JavaScript. */
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Printf.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/Exceptions.h"
 #include "nsString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -159,20 +159,23 @@ void
 XPCThrower::Verbosify(XPCCallContext& ccx,
                       char** psz, bool own)
 {
     char* sz = nullptr;
 
     if (ccx.HasInterfaceAndMember()) {
         XPCNativeInterface* iface = ccx.GetInterface();
         jsid id = ccx.GetMember()->GetName();
-        JSAutoByteString bytes;
-        const char* name = JSID_IS_VOID(id) ? "Unknown" : bytes.encodeLatin1(ccx, JSID_TO_STRING(id));
-        if (!name) {
-            name = "";
+        const char* name;
+        JS::UniqueChars bytes;
+        if (!JSID_IS_VOID(id)) {
+            bytes = JS_EncodeString(ccx, JSID_TO_STRING(id));
+            name = bytes ? bytes.get() : "";
+        } else {
+            name = "Unknown";
         }
         sz = JS_smprintf("%s [%s.%s]", *psz, iface->GetNameString(), name).release();
     }
 
     if (sz) {
         if (own)
             js_free(*psz);
         *psz = sz;
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */
 
 #include "xpcprivate.h"
 #include "xpc_make_class.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Preferences.h"
-#include "js/AutoByteString.h"
+#include "js/CharacterEncoding.h"
 #include "js/Class.h"
 #include "js/Printf.h"
 
 using namespace mozilla;
 using namespace JS;
 
 /***************************************************************************/
 
@@ -284,30 +284,47 @@ DefinePropertyIfFound(XPCCallContext& cc
             }
         }
         // This *might* be a tearoff name that is not yet part of our
         // set. Let's lookup the name and see if it is the name of an
         // interface. Then we'll see if the object actually *does* this
         // interface and add a tearoff as necessary.
 
         if (wrapperToReflectInterfaceNames) {
-            JSAutoByteString name;
+            JS::UniqueChars name;
             RefPtr<XPCNativeInterface> iface2;
             XPCWrappedNativeTearOff* to;
             RootedObject jso(ccx);
             nsresult rv = NS_OK;
 
-            if (JSID_IS_STRING(id) &&
-                name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
-                (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr())) &&
-                nullptr != (to = wrapperToReflectInterfaceNames->
-                           FindTearOff(iface2, true, &rv)) &&
-                nullptr != (jso = to->GetJSObject()))
+            bool defineProperty = false;
+            do {
+                if (!JSID_IS_STRING(id))
+                    break;
+
+                name = JS_EncodeString(ccx, JSID_TO_STRING(id));
+                if (!name)
+                    break;
+
+                iface2 = XPCNativeInterface::GetNewOrUsed(name.get());
+                if (!iface2)
+                    break;
 
-            {
+                to = wrapperToReflectInterfaceNames->FindTearOff(iface2, true, &rv);
+                if (!to)
+                    break;
+
+                jso = to->GetJSObject();
+                if (!jso)
+                    break;
+
+                defineProperty = true;
+            } while (false);
+
+            if (defineProperty) {
                 AutoResolveName arn(ccx, id);
                 if (resolved)
                     *resolved = true;
                 return JS_DefinePropertyById(ccx, obj, id, jso,
                                              propFlags & ~JSPROP_ENUMERATE);
             } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) {
                 return Throw(rv, ccx);
             }
--- a/toolkit/recordreplay/ipc/JSControl.cpp
+++ b/toolkit/recordreplay/ipc/JSControl.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "JSControl.h"
 
+#include "js/CharacterEncoding.h"
 #include "js/Conversions.h"
 #include "js/JSON.h"
 #include "ChildInternal.h"
 #include "ParentInternal.h"
 #include "xpcprivate.h"
 
 using namespace JS;
 
@@ -797,22 +798,21 @@ RecordReplay_Dump(JSContext* aCx, unsign
   // This method is an alternative to dump() that can be used in places where
   // thread events are disallowed.
   CallArgs args = CallArgsFromVp(aArgc, aVp);
   for (size_t i = 0; i < args.length(); i++) {
     RootedString str(aCx, ToString(aCx, args[i]));
     if (!str) {
       return false;
     }
-    char* cstr = JS_EncodeString(aCx, str);
+    JS::UniqueChars cstr = JS_EncodeString(aCx, str);
     if (!cstr) {
       return false;
     }
-    Print("%s", cstr);
-    JS_free(aCx, cstr);
+    Print("%s", cstr.get());
   }
 
   args.rval().setUndefined();
   return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Plumbing
--- a/tools/fuzzing/messagemanager/MessageManagerFuzzer.cpp
+++ b/tools/fuzzing/messagemanager/MessageManagerFuzzer.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 <climits>
 #include <cmath>
 #include "FuzzingTraits.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/CharacterEncoding.h"
 #include "prenv.h"
 #include "MessageManagerFuzzer.h"
 #include "mozilla/ErrorResult.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsFrameMessageManager.h"
 #include "nsJSUtils.h"
 #include "nsXULAppAPI.h"
@@ -190,19 +191,20 @@ MessageManagerFuzzer::MutateValue(JSCont
 
   if (aValue.isString()) {
     nsCString x = GetFuzzValueFromFile();
     if (x.IsEmpty()) {
       return false;
     }
     JSString* str = JS_NewStringCopyZ(aCx, x.get());
     aOutMutationValue.set(JS::StringValue(str));
+    JS::UniqueChars valueChars = JS_EncodeString(aCx, aValue.toString());
     MSGMGR_FUZZER_LOG("%*s! Mutated value of type |string|: '%s' to '%s'",
                       aRecursionCounter * 4, "",
-                      JS_EncodeString(aCx, aValue.toString()), x.get());
+                      valueChars.get(), x.get());
     return true;
   }
 
   if (aValue.isObject()) {
     aRecursionCounter++;
     MSGMGR_FUZZER_LOG("%*s<Enumerating found object>",
                       aRecursionCounter * 4, "");
     MutateObject(aCx, aValue, aRecursionCounter);
@@ -253,19 +255,20 @@ MessageManagerFuzzer::Mutate(JSContext* 
   }
 
   // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1346040
   aData->Copy(mutatedStructuredCloneData);
 
   /* Mutated and successfully written to StructuredCloneData object. */
   if (isMutated) {
     JS::RootedString str(aCx, JS_ValueToSource(aCx, scdMutationContent));
+    JS::UniqueChars strChars = JS_EncodeStringToUTF8(aCx, str);
     MSGMGR_FUZZER_LOG("Mutated '%s' Message: %s",
                       NS_ConvertUTF16toUTF8(aMessageName).get(),
-                      JS_EncodeStringToUTF8(aCx, str));
+                      strChars.get());
   }
 
   return true;
 }
 
 /* static */
 unsigned int
 MessageManagerFuzzer::DefaultMutationProbability()