Bug 1040316 - Move AutoStableStringChars out of friendapi into public API. r=jandem
authorJeff Walden <jwalden@mit.edu>
Mon, 20 Aug 2018 07:44:44 -0700
changeset 432536 6d10eda7f12de64044246e544d581537f30f8998
parent 432535 e0e6b77fb800d5b81c5b68af3dde3c4beee68d7a
child 432537 fa2218b2f4f17c47f39243914e9987eec1d51d38
push id34478
push userdluca@mozilla.com
push dateTue, 21 Aug 2018 09:54:49 +0000
treeherdermozilla-central@a955df76e2b6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1040316
milestone63.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 1040316 - Move AutoStableStringChars out of friendapi into public API. r=jandem
dom/base/nsJSUtils.h
dom/bindings/BindingUtils.cpp
dom/script/ScriptSettings.cpp
js/public/StableStringChars.h
js/src/builtin/Eval.cpp
js/src/builtin/JSON.cpp
js/src/builtin/ReflectParse.cpp
js/src/builtin/String.cpp
js/src/builtin/TestingFunctions.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/ctypes/CTypes.cpp
js/src/ctypes/Library.cpp
js/src/jsapi.cpp
js/src/jsfriendapi.h
js/src/moz.build
js/src/proxy/Proxy.cpp
js/src/proxy/SecurityWrapper.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Compartment.cpp
js/src/vm/Debugger.cpp
js/src/vm/JSFunction.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/Runtime.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
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -15,16 +15,17 @@
  */
 
 #include "mozilla/Assertions.h"
 
 #include "GeckoProfiler.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/Conversions.h"
+#include "js/StableStringChars.h"
 #include "nsString.h"
 
 class nsIScriptContext;
 class nsIScriptElement;
 class nsIScriptGlobalObject;
 class nsXBLPrototypeBinding;
 
 namespace mozilla {
@@ -220,17 +221,17 @@ public:
 
   static void ResetTimeZone();
 };
 
 template<typename T>
 inline bool
 AssignJSString(JSContext *cx, T &dest, JSString *s)
 {
-  size_t len = js::GetStringLength(s);
+  size_t len = JS::GetStringLength(s);
   static_assert(js::MaxStringLength < (1 << 28),
                 "Shouldn't overflow here or in SetCapacity");
   if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
     JS_ReportOutOfMemory(cx);
     return false;
   }
   return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
 }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "mozilla/UseCounter.h"
 
 #include "AccessCheck.h"
+#include "js/StableStringChars.h"
 #include "jsfriendapi.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsHTMLTags.h"
 #include "nsIDocShell.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsINode.h"
@@ -2853,17 +2854,17 @@ ConvertJSValueToByteString(JSContext* cx
       // terminator.
       char badCharArray[6];
       static_assert(sizeof(char16_t) <= 2, "badCharArray too small");
       SprintfLiteral(badCharArray, "%d", badChar);
       ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badCharArray);
       return false;
     }
   } else {
-    length = js::GetStringLength(s);
+    length = JS::GetStringLength(s);
   }
 
   static_assert(js::MaxStringLength < UINT32_MAX,
                 "length+1 shouldn't overflow");
 
   if (!result.SetLength(length, fallible)) {
     return false;
   }
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/dom/WorkerPrivate.h"
 
 #include "jsapi.h"
+#include "js/StableStringChars.h"
 #include "xpcpublic.h"
 #include "nsIGlobalObject.h"
 #include "nsIDocShell.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsPIDOMWindow.h"
@@ -705,17 +706,17 @@ AutoEntryScript::DocshellEntryMonitor::E
       !window->GetDocShell()->GetRecordProfileTimelineMarkers()) {
     return;
   }
 
   nsCOMPtr<nsIDocShell> docShellForJSRunToCompletion = window->GetDocShell();
   nsString filename;
   uint32_t lineNumber = 0;
 
-  js::AutoStableStringChars functionName(aCx);
+  JS::AutoStableStringChars functionName(aCx);
   if (rootedFunction) {
     JS::Rooted<JSString*> displayId(aCx, JS_GetFunctionDisplayId(rootedFunction));
     if (displayId) {
       if (!functionName.initTwoByte(aCx, displayId)) {
         JS_ClearPendingException(aCx);
         return;
       }
     }
new file mode 100644
--- /dev/null
+++ b/js/public/StableStringChars.h
@@ -0,0 +1,123 @@
+/* -*- 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/. */
+
+/*
+ * Safely access the contents of a string even as GC can cause the string's
+ * contents to move around in memory.
+ */
+
+#ifndef js_StableStringChars_h
+#define js_StableStringChars_h
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS, MOZ_MUST_USE
+#include "mozilla/Maybe.h" // mozilla::Maybe
+#include "mozilla/Range.h" // mozilla::Range
+
+#include <stddef.h> // size_t
+#include <stdint.h> // uint8_t
+
+#include "jstypes.h" // JS_FRIEND_API
+
+#include "js/HeapAPI.h" // JS::shadow::String
+#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
+#include "js/TypeDecls.h" // JSContext, JS::Latin1Char, JSString
+#include "js/Vector.h" // js::Vector
+
+class JSLinearString;
+
+namespace JS {
+
+MOZ_ALWAYS_INLINE size_t
+GetStringLength(JSString* s)
+{
+    return reinterpret_cast<shadow::String*>(s)->length();
+}
+
+/**
+ * This class provides safe access to a string's chars across a GC. Once
+ * we allocate strings and chars in the nursery (bug 903519), this class
+ * will have to make a copy of the string's chars if they are allocated
+ * in the nursery, so it's best to avoid using this class unless you really
+ * need it. It's usually more efficient to use the latin1Chars/twoByteChars
+ * JSString methods and often the code can be rewritten so that only indexes
+ * instead of char pointers are used in parts of the code that can GC.
+ */
+class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars) final
+{
+    /*
+     * When copying string char, use this many bytes of inline storage.  This is
+     * chosen to allow the inline string types to be copied without allocating.
+     * This is asserted in AutoStableStringChars::allocOwnChars.
+     */
+    static const size_t InlineCapacity = 24;
+
+    /* Ensure the string is kept alive while we're using its chars. */
+    Rooted<JSString*> s_;
+    MOZ_INIT_OUTSIDE_CTOR union {
+        const char16_t* twoByteChars_;
+        const Latin1Char* latin1Chars_;
+    };
+    mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_;
+    enum State { Uninitialized, Latin1, TwoByte };
+    State state_;
+
+  public:
+    explicit AutoStableStringChars(JSContext* cx)
+      : s_(cx), state_(Uninitialized)
+    {}
+
+    MOZ_MUST_USE bool init(JSContext* cx, JSString* s);
+
+    /* Like init(), but Latin1 chars are inflated to TwoByte. */
+    MOZ_MUST_USE bool initTwoByte(JSContext* cx, JSString* s);
+
+    bool isLatin1() const { return state_ == Latin1; }
+    bool isTwoByte() const { return state_ == TwoByte; }
+
+    const Latin1Char* latin1Chars() const {
+        MOZ_ASSERT(state_ == Latin1);
+        return latin1Chars_;
+    }
+    const char16_t* twoByteChars() const {
+        MOZ_ASSERT(state_ == TwoByte);
+        return twoByteChars_;
+    }
+
+    mozilla::Range<const Latin1Char> latin1Range() const {
+        MOZ_ASSERT(state_ == Latin1);
+        return mozilla::Range<const Latin1Char>(latin1Chars_, GetStringLength(s_));
+    }
+
+    mozilla::Range<const char16_t> twoByteRange() const {
+        MOZ_ASSERT(state_ == TwoByte);
+        return mozilla::Range<const char16_t>(twoByteChars_,
+                                              GetStringLength(s_));
+    }
+
+    /* If we own the chars, transfer ownership to the caller. */
+    bool maybeGiveOwnershipToCaller() {
+        MOZ_ASSERT(state_ != Uninitialized);
+        if (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
+            return false;
+        state_ = Uninitialized;
+        ownChars_.reset();
+        return true;
+    }
+
+  private:
+    AutoStableStringChars(const AutoStableStringChars& other) = delete;
+    void operator=(const AutoStableStringChars& other) = delete;
+
+    bool baseIsInline(Handle<JSLinearString*> linearString);
+    template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
+    bool copyLatin1Chars(JSContext* cx, Handle<JSLinearString*> linearString);
+    bool copyTwoByteChars(JSContext* cx, Handle<JSLinearString*> linearString);
+    bool copyAndInflateLatin1Chars(JSContext*, Handle<JSLinearString*> linearString);
+};
+
+} // namespace JS
+
+#endif /* js_StableStringChars_h */
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -6,30 +6,32 @@
 
 #include "builtin/Eval.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Range.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "gc/HashUtil.h"
+#include "js/StableStringChars.h"
 #include "vm/Debugger.h"
 #include "vm/GlobalObject.h"
 #include "vm/JSContext.h"
 #include "vm/JSONParser.h"
 
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 
 using mozilla::AddToHash;
 using mozilla::HashString;
 using mozilla::RangedPtr;
 
 using JS::AutoCheckCannotGC;
+using JS::AutoStableStringChars;
 
 // We should be able to assert this for *any* fp->environmentChain().
 static void
 AssertInnerizedEnvironmentChain(JSContext* cx, JSObject& env)
 {
 #ifdef DEBUG
     RootedObject obj(cx);
     for (obj = &env; obj; obj = obj->enclosingEnvironment())
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -14,16 +14,17 @@
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "builtin/Array.h"
 #ifdef ENABLE_BIGINT
 #include "builtin/BigInt.h"
 #endif
 #include "builtin/String.h"
+#include "js/StableStringChars.h"
 #include "util/StringBuffer.h"
 #include "vm/Interpreter.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSONParser.h"
 
 #include "builtin/Array-inl.h"
@@ -33,16 +34,18 @@
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::IsFinite;
 using mozilla::Maybe;
 using mozilla::RangedPtr;
 
+using JS::AutoStableStringChars;
+
 const Class js::JSONClass = {
     js_JSON_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON)
 };
 
 /* ES5 15.12.3 Quote.
  * Requires that the destination has enough space allocated for src after escaping
  * (that is, `2 + 6 * (srcEnd - srcBegin)` characters).
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -14,26 +14,28 @@
 
 #include "jspubtd.h"
 
 #include "builtin/Array.h"
 #include "builtin/Reflect.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 #include "js/CharacterEncoding.h"
+#include "js/StableStringChars.h"
 #include "vm/JSAtom.h"
 #include "vm/JSObject.h"
 #include "vm/RegExpObject.h"
 
 #include "frontend/ParseNode-inl.h"
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 
+using JS::AutoStableStringChars;
 using JS::AutoValueArray;
 using mozilla::DebugOnly;
 
 enum ASTType {
     AST_ERROR = -1,
 #define ASTDEF(ast, str, method) ast,
 #include "jsast.tbl"
 #undef ASTDEF
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -26,16 +26,17 @@
 
 #include "builtin/Array.h"
 #include "builtin/Boolean.h"
 #include "builtin/intl/CommonFunctions.h"
 #include "builtin/intl/ICUStubs.h"
 #include "builtin/RegExp.h"
 #include "jit/InlinableNatives.h"
 #include "js/Conversions.h"
+#include "js/StableStringChars.h"
 #include "js/UniquePtr.h"
 #if ENABLE_INTL_API
 # include "unicode/uchar.h"
 # include "unicode/unorm2.h"
 #endif
 #include "util/StringBuffer.h"
 #include "util/Unicode.h"
 #include "vm/BytecodeUtil.h"
@@ -63,16 +64,17 @@ using JS::SymbolCode;
 
 using mozilla::CheckedInt;
 using mozilla::IsNaN;
 using mozilla::IsSame;
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
 
 using JS::AutoCheckCannotGC;
+using JS::AutoStableStringChars;
 
 static JSLinearString*
 ArgToLinearString(JSContext* cx, const CallArgs& args, unsigned argno)
 {
     if (argno >= args.length())
         return cx->names().undefined;
 
     JSString* str = ToString<CanGC>(cx, args[argno]);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -38,16 +38,17 @@
 #include "irregexp/RegExpParser.h"
 #endif
 #include "gc/Heap.h"
 #include "jit/BaselineJIT.h"
 #include "jit/InlinableNatives.h"
 #include "jit/JitRealm.h"
 #include "js/Debug.h"
 #include "js/HashTable.h"
+#include "js/StableStringChars.h"
 #include "js/StructuredClone.h"
 #include "js/UbiNode.h"
 #include "js/UbiNodeBreadthFirst.h"
 #include "js/UbiNodeShortestPaths.h"
 #include "js/UniquePtr.h"
 #include "js/Vector.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
@@ -80,16 +81,18 @@
 #include "vm/NativeObject-inl.h"
 #include "vm/StringType-inl.h"
 
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
+using JS::AutoStableStringChars;
+
 // If fuzzingSafe is set, remove functionality that could cause problems with
 // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
 mozilla::Atomic<bool> fuzzingSafe(false);
 
 // If disableOOMFunctions is set, disable functionality that causes artificial
 // OOM conditions.
 static mozilla::Atomic<bool> disableOOMFunctions(false);
 
--- a/js/src/builtin/intl/Collator.cpp
+++ b/js/src/builtin/intl/Collator.cpp
@@ -12,26 +12,29 @@
 
 #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/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"
 
 using namespace js;
 
+using JS::AutoStableStringChars;
+
 using js::intl::GetAvailableLocales;
 using js::intl::IcuLocale;
 using js::intl::ReportInternalError;
 using js::intl::SharedIntlData;
 using js::intl::StringsAreEqual;
 
 const ClassOps CollatorObject::classOps_ = {
     nullptr, /* addProperty */
--- a/js/src/builtin/intl/DateTimeFormat.cpp
+++ b/js/src/builtin/intl/DateTimeFormat.cpp
@@ -14,26 +14,28 @@
 #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/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"
 
 using namespace js;
 
+using JS::AutoStableStringChars;
 using JS::ClippedTime;
 using JS::TimeClip;
 
 using js::intl::CallICU;
 using js::intl::DateTimeFormatOptions;
 using js::intl::GetAvailableLocales;
 using js::intl::IcuLocale;
 using js::intl::INITIAL_CHAR_BUFFER_SIZE;
--- a/js/src/builtin/intl/IntlObject.cpp
+++ b/js/src/builtin/intl/IntlObject.cpp
@@ -17,28 +17,31 @@
 #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/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"
 
 using namespace js;
 
 using mozilla::Range;
 using mozilla::RangedPtr;
 
+using JS::AutoStableStringChars;
+
 using js::intl::CallICU;
 using js::intl::DateTimeFormatOptions;
 using js::intl::IcuLocale;
 
 /******************** Intl ********************/
 
 bool
 js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/builtin/intl/NumberFormat.cpp
+++ b/js/src/builtin/intl/NumberFormat.cpp
@@ -16,16 +16,17 @@
 #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/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"
 
 using namespace js;
@@ -35,16 +36,18 @@ using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
 
 using js::intl::CallICU;
 using js::intl::DateTimeFormatOptions;
 using js::intl::GetAvailableLocales;
 using js::intl::IcuLocale;
 
+using JS::AutoStableStringChars;
+
 const ClassOps NumberFormatObject::classOps_ = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* enumerate */
     nullptr, /* newEnumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     NumberFormatObject::finalize
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -35,30 +35,32 @@
 #include "jsnum.h"
 
 #include "builtin/TypedObject.h"
 #include "ctypes/Library.h"
 #include "gc/FreeOp.h"
 #include "gc/Policy.h"
 #include "gc/Zone.h"
 #include "jit/AtomicOperations.h"
+#include "js/StableStringChars.h"
 #include "js/UniquePtr.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;
 
 using mozilla::IsAsciiAlpha;
 using mozilla::IsAsciiDigit;
 
 using JS::AutoCheckCannotGC;
+using JS::AutoStableStringChars;
 
 namespace js {
 namespace ctypes {
 
 template <typename CharT>
 size_t
 GetDeflatedUTF8StringLength(JSContext* maybecx, const CharT* chars,
                             size_t nchars)
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -5,16 +5,19 @@
  * 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/StableStringChars.h"
+
+using JS::AutoStableStringChars;
 
 namespace js {
 namespace ctypes {
 
 /*******************************************************************************
 ** JSAPI function prototypes
 *******************************************************************************/
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -56,16 +56,17 @@
 #include "jit/JitCommon.h"
 #include "jit/JitSpewer.h"
 #include "js/CharacterEncoding.h"
 #include "js/Conversions.h"
 #include "js/Date.h"
 #include "js/Initialization.h"
 #include "js/Proxy.h"
 #include "js/SliceBudget.h"
+#include "js/StableStringChars.h"
 #include "js/StructuredClone.h"
 #include "js/Utility.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
 #include "vm/DateObject.h"
@@ -103,16 +104,18 @@
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::Maybe;
 using mozilla::PodCopy;
 using mozilla::Some;
 
+using JS::AutoStableStringChars;
+
 #ifdef HAVE_VA_LIST_AS_ARRAY
 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list*)(ap))
 #else
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
 
 JS_PUBLIC_API(bool)
 JS::CallArgs::requireAtLeast(JSContext* cx, const char* fnname, unsigned required) const
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -15,16 +15,17 @@
 
 #include "jsapi.h" // For JSAutoByteString.  See bug 1033916.
 #include "jspubtd.h"
 
 #include "js/CallArgs.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/Class.h"
 #include "js/HeapAPI.h"
+#include "js/StableStringChars.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 #ifndef JS_STACK_GROWTH_DIRECTION
 # ifdef __hppa
 #  define JS_STACK_GROWTH_DIRECTION (1)
 # else
 #  define JS_STACK_GROWTH_DIRECTION (-1)
@@ -33,17 +34,16 @@
 
 #if JS_STACK_GROWTH_DIRECTION > 0
 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit)))
 #else
 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit)))
 #endif
 
 struct JSErrorFormatString;
-class JSLinearString;
 struct JSJitInfo;
 class JSErrorReport;
 
 namespace JS {
 template <class T>
 class Heap;
 } /* namespace JS */
 
@@ -796,22 +796,16 @@ MOZ_ALWAYS_INLINE size_t
 GetAtomLength(JSAtom* atom)
 {
     return reinterpret_cast<JS::shadow::String*>(atom)->length();
 }
 
 static const uint32_t MaxStringLength = (1 << 28) - 1;
 
 MOZ_ALWAYS_INLINE size_t
-GetStringLength(JSString* s)
-{
-    return reinterpret_cast<JS::shadow::String*>(s)->length();
-}
-
-MOZ_ALWAYS_INLINE size_t
 GetFlatStringLength(JSFlatString* s)
 {
     return reinterpret_cast<JS::shadow::String*>(s)->length();
 }
 
 MOZ_ALWAYS_INLINE size_t
 GetLinearStringLength(JSLinearString* s)
 {
@@ -1393,104 +1387,16 @@ typedef enum JSErrNum {
 
 namespace js {
 
 /* Implemented in vm/JSContext.cpp. */
 
 extern JS_FRIEND_API(const JSErrorFormatString*)
 GetErrorMessage(void* userRef, const unsigned errorNumber);
 
-// AutoStableStringChars is here so we can use it in ErrorReport.  It
-// should get moved out of here if we can manage it.  See bug 1040316.
-
-/**
- * This class provides safe access to a string's chars across a GC. Once
- * we allocate strings and chars in the nursery (bug 903519), this class
- * will have to make a copy of the string's chars if they are allocated
- * in the nursery, so it's best to avoid using this class unless you really
- * need it. It's usually more efficient to use the latin1Chars/twoByteChars
- * JSString methods and often the code can be rewritten so that only indexes
- * instead of char pointers are used in parts of the code that can GC.
- */
-class MOZ_STACK_CLASS JS_FRIEND_API(AutoStableStringChars)
-{
-    /*
-     * When copying string char, use this many bytes of inline storage.  This is
-     * chosen to allow the inline string types to be copied without allocating.
-     * This is asserted in AutoStableStringChars::allocOwnChars.
-     */
-    static const size_t InlineCapacity = 24;
-
-    /* Ensure the string is kept alive while we're using its chars. */
-    JS::RootedString s_;
-    MOZ_INIT_OUTSIDE_CTOR union {
-        const char16_t* twoByteChars_;
-        const JS::Latin1Char* latin1Chars_;
-    };
-    mozilla::Maybe<Vector<uint8_t, InlineCapacity>> ownChars_;
-    enum State { Uninitialized, Latin1, TwoByte };
-    State state_;
-
-  public:
-    explicit AutoStableStringChars(JSContext* cx)
-      : s_(cx), state_(Uninitialized)
-    {}
-
-    MOZ_MUST_USE
-    bool init(JSContext* cx, JSString* s);
-
-    /* Like init(), but Latin1 chars are inflated to TwoByte. */
-    MOZ_MUST_USE
-    bool initTwoByte(JSContext* cx, JSString* s);
-
-    bool isLatin1() const { return state_ == Latin1; }
-    bool isTwoByte() const { return state_ == TwoByte; }
-
-    const JS::Latin1Char* latin1Chars() const {
-        MOZ_ASSERT(state_ == Latin1);
-        return latin1Chars_;
-    }
-    const char16_t* twoByteChars() const {
-        MOZ_ASSERT(state_ == TwoByte);
-        return twoByteChars_;
-    }
-
-    mozilla::Range<const JS::Latin1Char> latin1Range() const {
-        MOZ_ASSERT(state_ == Latin1);
-        return mozilla::Range<const JS::Latin1Char>(latin1Chars_,
-                                                    GetStringLength(s_));
-    }
-
-    mozilla::Range<const char16_t> twoByteRange() const {
-        MOZ_ASSERT(state_ == TwoByte);
-        return mozilla::Range<const char16_t>(twoByteChars_,
-                                              GetStringLength(s_));
-    }
-
-    /* If we own the chars, transfer ownership to the caller. */
-    bool maybeGiveOwnershipToCaller() {
-        MOZ_ASSERT(state_ != Uninitialized);
-        if (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
-            return false;
-        state_ = Uninitialized;
-        ownChars_.reset();
-        return true;
-    }
-
-  private:
-    AutoStableStringChars(const AutoStableStringChars& other) = delete;
-    void operator=(const AutoStableStringChars& other) = delete;
-
-    bool baseIsInline(JS::Handle<JSLinearString*> linearString);
-    template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
-    bool copyLatin1Chars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
-    bool copyTwoByteChars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
-    bool copyAndInflateLatin1Chars(JSContext*, JS::Handle<JSLinearString*> linearString);
-};
-
 struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport)
 {
     explicit ErrorReport(JSContext* cx);
     ~ErrorReport();
 
     enum SniffingBehavior {
         WithSideEffects,
         NoSideEffects
@@ -1556,17 +1462,17 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(Err
     // Or we may need to synthesize a JSErrorReport one of our own.
     JSErrorReport ownedReport;
 
     // And we have a string to maybe keep alive that has pointers into
     // it from ownedReport.
     JS::RootedString str;
 
     // And keep its chars alive too.
-    AutoStableStringChars strChars;
+    JS::AutoStableStringChars strChars;
 
     // And we need to root our exception value.
     JS::RootedObject exnObject;
 
     // And for our filename.
     JSAutoByteString filename;
 
     // We may have a result of error.toString().
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -149,16 +149,17 @@ EXPORTS.js += [
     '../public/ProtoKey.h',
     '../public/Proxy.h',
     '../public/Realm.h',
     '../public/RefCounted.h',
     '../public/RequiredDefines.h',
     '../public/Result.h',
     '../public/RootingAPI.h',
     '../public/SliceBudget.h',
+    '../public/StableStringChars.h',
     '../public/Stream.h',
     '../public/StructuredClone.h',
     '../public/SweepingAPI.h',
     '../public/TraceKind.h',
     '../public/TracingAPI.h',
     '../public/TrackedOptimizationInfo.h',
     '../public/TypeDecls.h',
     '../public/UbiNode.h',
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -7,31 +7,34 @@
 #include "js/Proxy.h"
 
 #include "mozilla/Attributes.h"
 
 #include <string.h>
 
 #include "jsapi.h"
 
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "proxy/DeadObjectProxy.h"
 #include "proxy/ScriptedProxyHandler.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/WrapperObject.h"
 
 #include "gc/Marking-inl.h"
 #include "vm/JSAtom-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+using JS::AutoStableStringChars;
+
 void
 js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id)
 {
     if (JS_IsExceptionPending(cx))
         return;
 
     if (JSID_IS_VOID(id)) {
         ReportAccessDenied(cx);
--- a/js/src/proxy/SecurityWrapper.cpp
+++ b/js/src/proxy/SecurityWrapper.cpp
@@ -3,21 +3,24 @@
  * 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 "jsapi.h"
 #include "jsfriendapi.h"
 #include "NamespaceImports.h"
 
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "vm/StringType.h"
 
 using namespace js;
 
+using JS::AutoStableStringChars;
+
 template <class Base>
 bool
 SecurityWrapper<Base>::enter(JSContext* cx, HandleObject wrapper, HandleId id,
                              Wrapper::Action act, bool mayThrow, bool* bp) const
 {
     ReportAccessDenied(cx);
     *bp = false;
     return false;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -76,16 +76,17 @@
 #include "jit/Ion.h"
 #include "jit/JitcodeMap.h"
 #include "jit/JitRealm.h"
 #include "jit/shared/CodeGenerator-shared.h"
 #include "js/Debug.h"
 #include "js/GCVector.h"
 #include "js/Initialization.h"
 #include "js/Printf.h"
+#include "js/StableStringChars.h"
 #include "js/StructuredClone.h"
 #include "js/SweepingAPI.h"
 #include "js/Wrapper.h"
 #include "perf/jsperf.h"
 #include "shell/jsoptparse.h"
 #include "shell/jsshell.h"
 #include "shell/OSObject.h"
 #include "threading/ConditionVariable.h"
@@ -121,16 +122,18 @@
 #include "vm/JSObject-inl.h"
 #include "vm/Realm-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::cli;
 using namespace js::shell;
 
+using JS::AutoStableStringChars;
+
 using js::shell::RCFile;
 
 using mozilla::ArrayEqual;
 using mozilla::ArrayLength;
 using mozilla::Atomic;
 using mozilla::MakeScopeExit;
 using mozilla::Maybe;
 using mozilla::Nothing;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -5,28 +5,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "vm/ArgumentsObject-inl.h"
 
 #include "mozilla/PodOperations.h"
 
 #include "gc/FreeOp.h"
 #include "jit/JitFrames.h"
+#include "js/StableStringChars.h"
 #include "vm/AsyncFunction.h"
 #include "vm/GlobalObject.h"
 #include "vm/Stack.h"
 
 #include "gc/Nursery-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+using JS::AutoStableStringChars;
+
 /* static */ size_t
 RareArgumentsData::bytesRequired(size_t numActuals)
 {
     size_t extraBytes = NumWordsForBitArrayOfLength(numActuals) * sizeof(size_t);
     return offsetof(RareArgumentsData, deletedBits_) + extraBytes;
 }
 
 /* static */ RareArgumentsData*
--- a/js/src/vm/Compartment.cpp
+++ b/js/src/vm/Compartment.cpp
@@ -12,16 +12,17 @@
 
 #include "jsfriendapi.h"
 
 #include "gc/Policy.h"
 #include "gc/PublicIterators.h"
 #include "js/Date.h"
 #include "js/Proxy.h"
 #include "js/RootingAPI.h"
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "proxy/DeadObjectProxy.h"
 #include "vm/Debugger.h"
 #include "vm/Iteration.h"
 #include "vm/JSContext.h"
 #include "vm/WrapperObject.h"
 
 #include "gc/GC-inl.h"
@@ -31,16 +32,18 @@
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+using JS::AutoStableStringChars;
+
 Compartment::Compartment(Zone* zone)
   : zone_(zone),
     runtime_(zone->runtimeFromAnyThread()),
     crossCompartmentWrappers(0)
 {}
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -21,16 +21,17 @@
 #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/Date.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"
 #include "vm/ArgumentsObject.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
@@ -50,16 +51,17 @@
 #include "vm/GeckoProfiler-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 
+using JS::AutoStableStringChars;
 using JS::dbg::AutoEntryMonitor;
 using JS::dbg::Builder;
 using js::frontend::IsIdentifier;
 using mozilla::DebugOnly;
 using mozilla::MakeScopeExit;
 using mozilla::Maybe;
 using mozilla::Some;
 using mozilla::Nothing;
@@ -5031,17 +5033,17 @@ Debugger::isCompilableUnit(JSContext* cx
     if (!args[0].isString()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                                   "Debugger.isCompilableUnit", "string",
                                   InformalValueTypeName(args[0]));
         return false;
     }
 
     JSString* str = args[0].toString();
-    size_t length = GetStringLength(str);
+    size_t length = str->length();
 
     AutoStableStringChars chars(cx);
     if (!chars.initTwoByte(cx, str))
         return false;
 
     bool result = true;
 
     CompileOptions options(cx);
--- a/js/src/vm/JSFunction.cpp
+++ b/js/src/vm/JSFunction.cpp
@@ -28,16 +28,17 @@
 #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/CallNonGenericMethod.h"
 #include "js/Proxy.h"
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "vm/AsyncFunction.h"
 #include "vm/AsyncIteration.h"
 #include "vm/Debugger.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/JSAtom.h"
@@ -59,16 +60,18 @@ using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 using mozilla::ArrayLength;
 using mozilla::CheckedInt;
 using mozilla::Maybe;
 using mozilla::Some;
 
+using JS::AutoStableStringChars;
+
 static bool
 fun_enumerate(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->is<JSFunction>());
 
     RootedId id(cx);
     bool found;
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -17,16 +17,17 @@
 #include "builtin/RegExp.h"
 #include "frontend/TokenStream.h"
 #include "gc/HashUtil.h"
 #ifdef DEBUG
 #include "irregexp/RegExpBytecode.h"
 #endif
 #include "irregexp/RegExpParser.h"
 #include "jit/VMFunctions.h"
+#include "js/StableStringChars.h"
 #include "util/StringBuffer.h"
 #include "vm/MatchPairs.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringType.h"
 #include "vm/TraceLogging.h"
 #ifdef DEBUG
 #include "util/Unicode.h"
 #endif
@@ -36,16 +37,17 @@
 #include "vm/NativeObject-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::DebugOnly;
 using mozilla::PodCopy;
+using JS::AutoStableStringChars;
 using js::frontend::TokenStream;
 
 using JS::AutoCheckCannotGC;
 
 JS_STATIC_ASSERT(IgnoreCaseFlag == JSREG_FOLD);
 JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
 JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
 JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -33,16 +33,17 @@
 #include "jit/arm64/vixl/Simulator-vixl.h"
 #include "jit/IonBuilder.h"
 #include "jit/JitRealm.h"
 #include "jit/mips32/Simulator-mips32.h"
 #include "jit/mips64/Simulator-mips64.h"
 #include "js/Date.h"
 #include "js/MemoryMetrics.h"
 #include "js/SliceBudget.h"
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/Windows.h"
 #include "vm/DateTime.h"
 #include "vm/Debugger.h"
 #include "vm/JSAtom.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/TraceLogging.h"
@@ -54,16 +55,17 @@
 using namespace js;
 using namespace js::gc;
 
 using mozilla::Atomic;
 using mozilla::DebugOnly;
 using mozilla::NegativeInfinity;
 using mozilla::PodZero;
 using mozilla::PositiveInfinity;
+using JS::AutoStableStringChars;
 using JS::DoubleNaNValue;
 
 /* static */ MOZ_THREAD_LOCAL(JSContext*) js::TlsContext;
 /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
 Atomic<JS::LargeAllocationFailureCallback> js::OnLargeAllocationFailure;
 
 namespace js {
     bool gCanUseExtraThreads = true;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -35,16 +35,17 @@
 #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/CharacterEncoding.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"
 #include "vm/GeneratorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 #include "vm/JSContext.h"
@@ -65,16 +66,17 @@
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::selfhosted;
 
 using JS::AutoCheckCannotGC;
+using JS::AutoStableStringChars;
 using mozilla::IsInRange;
 using mozilla::Maybe;
 
 static void
 selfHosting_WarningReporter(JSContext* cx, JSErrorReport* report)
 {
     MOZ_ASSERT(report);
     MOZ_ASSERT(JSREPORT_IS_WARNING(report->flags));
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -15,16 +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/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"
 #include "vm/Realm-inl.h"
@@ -36,16 +37,17 @@ using mozilla::IsAsciiDigit;
 using mozilla::IsNegativeZero;
 using mozilla::IsSame;
 using mozilla::PodCopy;
 using mozilla::RangedPtr;
 using mozilla::RoundUpPow2;
 using mozilla::Unused;
 
 using JS::AutoCheckCannotGC;
+using JS::AutoStableStringChars;
 
 using UniqueLatin1Chars = UniquePtr<Latin1Char[], JS::FreePolicy>;
 
 size_t
 JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     // JSRope: do nothing, we'll count all children chars when we hit the leaf strings.
     if (isRope())
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -27,19 +27,24 @@
 #include "vm/Printer.h"
 
 class JSDependentString;
 class JSExtensibleString;
 class JSExternalString;
 class JSInlineString;
 class JSRope;
 
+namespace JS {
+
+class AutoStableStringChars;
+
+} // namespace JS
+
 namespace js {
 
-class AutoStableStringChars;
 class StaticStrings;
 class PropertyName;
 
 /* The buffer length required to contain any unsigned 32-bit integer. */
 static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
 
 } /* namespace js */
 
@@ -805,17 +810,17 @@ class JSRope : public JSString
 };
 
 static_assert(sizeof(JSRope) == sizeof(JSString),
               "string subclasses must be binary-compatible with JSString");
 
 class JSLinearString : public JSString
 {
     friend class JSString;
-    friend class js::AutoStableStringChars;
+    friend class JS::AutoStableStringChars;
     friend class js::TenuringTracer;
 
     /* Vacuous and therefore unimplemented. */
     JSLinearString* ensureLinear(JSContext* cx) = delete;
     bool isLinear() const = delete;
     JSLinearString& asLinear() const = delete;
 
   protected:
--- a/js/src/vm/UbiNodeCensus.cpp
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -1,16 +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/StableStringChars.h"
 #include "util/Text.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -29,16 +29,17 @@
 #include "jsmath.h"
 #include "jsutil.h"
 
 #include "builtin/String.h"
 #include "frontend/Parser.h"
 #include "gc/Policy.h"
 #include "js/MemoryMetrics.h"
 #include "js/Printf.h"
+#include "js/StableStringChars.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/ErrorReporting.h"
 #include "vm/SelfHosting.h"
 #include "vm/Time.h"
 #include "vm/TypedArrayObject.h"
 #include "wasm/WasmCompile.h"
@@ -65,16 +66,17 @@ using mozilla::HashGeneric;
 using mozilla::IsNaN;
 using mozilla::IsNegativeZero;
 using mozilla::IsPositiveZero;
 using mozilla::IsPowerOfTwo;
 using mozilla::PodZero;
 using mozilla::PositiveInfinity;
 using mozilla::Unused;
 using JS::AsmJSOption;
+using JS::AutoStableStringChars;
 using JS::GenericNaN;
 
 /*****************************************************************************/
 
 // The asm.js valid heap lengths are precisely the WASM valid heap lengths for ARM
 // greater or equal to MinHeapLength
 static const size_t MinHeapLength = PageSize;