Bug 1118107 - Convert ThreadSafeContext -> ExclusiveContext and remove PJS paths in string and conversion ops. (r=lth)
authorShu-yu Guo <shu@rfrn.org>
Fri, 09 Jan 2015 00:06:03 -0800
changeset 248703 dfa1f0425c654d6058be1ef238c9d4a6e605f6ba
parent 248702 46c80c517631bd66053a9a84f8419329f7891935
child 248704 db4f4627bbc19bbf8063af46577c2221a8163c90
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1118107
milestone37.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 1118107 - Convert ThreadSafeContext -> ExclusiveContext and remove PJS paths in string and conversion ops. (r=lth)
js/public/CharacterEncoding.h
js/src/jit/CodeGenerator.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/vm/CharacterEncoding.cpp
js/src/vm/String-inl.h
js/src/vm/String.cpp
js/src/vm/String.h
--- a/js/public/CharacterEncoding.h
+++ b/js/public/CharacterEncoding.h
@@ -9,17 +9,17 @@
 
 #include "mozilla/NullPtr.h"
 #include "mozilla/Range.h"
 
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 namespace js {
-struct ThreadSafeContext;
+class ExclusiveContext;
 }
 
 class JSFlatString;
 
 namespace JS {
 
 /*
  * By default, all C/C++ 1-byte-per-character strings passed into the JSAPI
@@ -171,22 +171,22 @@ class ConstTwoByteChars : public mozilla
  * contains any UTF-16 extension characters, then this may give invalid Latin1
  * output. The returned string is zero terminated. The returned string or the
  * returned string's |start()| must be freed with JS_free or js_free,
  * respectively. If allocation fails, an OOM error will be set and the method
  * will return a nullptr chars (which can be tested for with the ! operator).
  * This method cannot trigger GC.
  */
 extern Latin1CharsZ
-LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx,
+LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext *cx,
                                    const mozilla::Range<const char16_t> tbchars);
 
 template <typename CharT>
 extern UTF8CharsZ
-CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars);
+CharsToNewUTF8CharsZ(js::ExclusiveContext *cx, const mozilla::Range<const CharT> chars);
 
 uint32_t
 Utf8ToOneUcs4Char(const uint8_t *utf8Buffer, int utf8Length);
 
 /*
  * Inflate bytes in UTF-8 encoding to char16_t.
  * - On error, returns an empty TwoByteCharsZ.
  * - On success, returns a malloc'd TwoByteCharsZ, and updates |outlen| to hold
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -158,17 +158,17 @@ CodeGenerator::CodeGenerator(MIRGenerato
 }
 
 CodeGenerator::~CodeGenerator()
 {
     MOZ_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
     js_delete(scriptCounts_);
 }
 
-typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
+typedef bool (*StringToNumberFn)(ExclusiveContext *, JSString *, double *);
 static const VMFunction StringToNumberInfo = FunctionInfo<StringToNumberFn>(StringToNumber);
 
 void
 CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
 {
     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
     Register output = ToRegister(lir->output());
     FloatRegister temp = ToFloatRegister(lir->tempFloat());
@@ -809,34 +809,34 @@ CodeGenerator::emitIntToString(Register 
 {
     masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
 
     // Fast path for small integers.
     masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().intStaticTable), output);
     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
 }
 
-typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
+typedef JSFlatString *(*IntToStringFn)(ExclusiveContext *, int);
 static const VMFunction IntToStringInfo = FunctionInfo<IntToStringFn>(Int32ToString<CanGC>);
 
 void
 CodeGenerator::visitIntToString(LIntToString *lir)
 {
     Register input = ToRegister(lir->input());
     Register output = ToRegister(lir->output());
 
     OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
                                    StoreRegisterTo(output));
 
     emitIntToString(input, output, ool->entry());
 
     masm.bind(ool->rejoin());
 }
 
-typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
+typedef JSString *(*DoubleToStringFn)(ExclusiveContext *, double);
 static const VMFunction DoubleToStringInfo = FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>);
 
 void
 CodeGenerator::visitDoubleToString(LDoubleToString *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register temp = ToRegister(lir->tempInt());
     Register output = ToRegister(lir->output());
@@ -5276,17 +5276,17 @@ CodeGenerator::visitEmulatesUndefinedAnd
         unequal = getJumpLabelForBranch(ifFalse);
     }
 
     Register objreg = ToRegister(lir->input());
 
     testObjectEmulatesUndefined(objreg, equal, unequal, ToRegister(lir->temp()), ool);
 }
 
-typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
+typedef JSString *(*ConcatStringsFn)(ExclusiveContext *, HandleString, HandleString);
 static const VMFunction ConcatStringsInfo = FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>);
 
 void
 CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
 {
     OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
                                    StoreRegisterTo(output));
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -58,17 +58,17 @@ using JS::ToUint64;
 
 /*
  * If we're accumulating a decimal number and the number is >= 2^53, then the
  * fast result from the loop in Get{Prefix,Decimal}Integer may be inaccurate.
  * Call js_strtod_harder to get the correct answer.
  */
 template <typename CharT>
 static bool
-ComputeAccurateDecimalInteger(ThreadSafeContext *cx, const CharT *start, const CharT *end,
+ComputeAccurateDecimalInteger(ExclusiveContext *cx, const CharT *start, const CharT *end,
                               double *dp)
 {
     size_t length = end - start;
     ScopedJSFreePtr<char> cstr(cx->pod_malloc<char>(length + 1));
     if (!cstr)
         return false;
 
     for (size_t i = 0; i < length; i++) {
@@ -203,17 +203,17 @@ js::ParseDecimalNumber(const mozilla::Ra
 template double
 js::ParseDecimalNumber(const mozilla::Range<const Latin1Char> chars);
 
 template double
 js::ParseDecimalNumber(const mozilla::Range<const char16_t> chars);
 
 template <typename CharT>
 bool
-js::GetPrefixInteger(ThreadSafeContext *cx, const CharT *start, const CharT *end, int base,
+js::GetPrefixInteger(ExclusiveContext *cx, const CharT *start, const CharT *end, int base,
                      const CharT **endp, double *dp)
 {
     MOZ_ASSERT(start <= end);
     MOZ_ASSERT(2 <= base && base <= 36);
 
     const CharT *s = start;
     double d = 0.0;
     for (; s < end; s++) {
@@ -249,21 +249,21 @@ js::GetPrefixInteger(ThreadSafeContext *
 
     if ((base & (base - 1)) == 0)
         *dp = ComputeAccurateBinaryBaseInteger(start, s, base);
 
     return true;
 }
 
 template bool
-js::GetPrefixInteger(ThreadSafeContext *cx, const char16_t *start, const char16_t *end, int base,
+js::GetPrefixInteger(ExclusiveContext *cx, const char16_t *start, const char16_t *end, int base,
                      const char16_t **endp, double *dp);
 
 template bool
-js::GetPrefixInteger(ThreadSafeContext *cx, const Latin1Char *start, const Latin1Char *end,
+js::GetPrefixInteger(ExclusiveContext *cx, const Latin1Char *start, const Latin1Char *end,
                      int base, const Latin1Char **endp, double *dp);
 
 bool
 js::GetDecimalInteger(ExclusiveContext *cx, const char16_t *start, const char16_t *end, double *dp)
 {
     MOZ_ASSERT(start <= end);
 
     const char16_t *s = start;
@@ -548,43 +548,37 @@ ToCStringBuf::ToCStringBuf() : dbuf(null
 
 ToCStringBuf::~ToCStringBuf()
 {
     js_free(dbuf);
 }
 
 MOZ_ALWAYS_INLINE
 static JSFlatString *
-LookupDtoaCache(ThreadSafeContext *cx, double d)
+LookupDtoaCache(ExclusiveContext *cx, double d)
 {
-    if (!cx->isExclusiveContext())
-        return nullptr;
-
-    if (JSCompartment *comp = cx->asExclusiveContext()->compartment()) {
+    if (JSCompartment *comp = cx->compartment()) {
         if (JSFlatString *str = comp->dtoaCache.lookup(10, d))
             return str;
     }
 
     return nullptr;
 }
 
 MOZ_ALWAYS_INLINE
 static void
-CacheNumber(ThreadSafeContext *cx, double d, JSFlatString *str)
+CacheNumber(ExclusiveContext *cx, double d, JSFlatString *str)
 {
-    if (!cx->isExclusiveContext())
-        return;
-
-    if (JSCompartment *comp = cx->asExclusiveContext()->compartment())
+    if (JSCompartment *comp = cx->compartment())
         comp->dtoaCache.cache(10, d, str);
 }
 
 MOZ_ALWAYS_INLINE
 static JSFlatString *
-LookupInt32ToString(ThreadSafeContext *cx, int32_t si)
+LookupInt32ToString(ExclusiveContext *cx, int32_t si)
 {
     if (si >= 0 && StaticStrings::hasInt(si))
         return cx->staticStrings().getInt(si);
 
     return LookupDtoaCache(cx, si);
 }
 
 template <typename T>
@@ -602,17 +596,17 @@ BackfillInt32InBuffer(int32_t si, T *buf
         *--start = '-';
 
     *length = end - start;
     return start.get();
 }
 
 template <AllowGC allowGC>
 JSFlatString *
-js::Int32ToString(ThreadSafeContext *cx, int32_t si)
+js::Int32ToString(ExclusiveContext *cx, int32_t si)
 {
     if (JSFlatString *str = LookupInt32ToString(cx, si))
         return str;
 
     Latin1Char buffer[JSFatInlineString::MAX_LENGTH_LATIN1 + 1];
     size_t length;
     Latin1Char *start = BackfillInt32InBuffer(si, buffer, ArrayLength(buffer), &length);
 
@@ -621,20 +615,20 @@ js::Int32ToString(ThreadSafeContext *cx,
     if (!str)
         return nullptr;
 
     CacheNumber(cx, si, str);
     return str;
 }
 
 template JSFlatString *
-js::Int32ToString<CanGC>(ThreadSafeContext *cx, int32_t si);
+js::Int32ToString<CanGC>(ExclusiveContext *cx, int32_t si);
 
 template JSFlatString *
-js::Int32ToString<NoGC>(ThreadSafeContext *cx, int32_t si);
+js::Int32ToString<NoGC>(ExclusiveContext *cx, int32_t si);
 
 JSAtom *
 js::Int32ToAtom(ExclusiveContext *cx, int32_t si)
 {
     if (JSFlatString *str = LookupInt32ToString(cx, si))
         return js::AtomizeString(cx, str);
 
     char buffer[JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1];
@@ -684,17 +678,17 @@ Int32ToCString(ToCStringBuf *cbuf, int32
         *--cp = '-';
 
     *len = end - cp.get();
     return cp.get();
 }
 
 template <AllowGC allowGC>
 static JSString * JS_FASTCALL
-js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base);
+js_NumberToStringWithBase(ExclusiveContext *cx, double d, int base);
 
 MOZ_ALWAYS_INLINE bool
 num_toString_impl(JSContext *cx, CallArgs args)
 {
     MOZ_ASSERT(IsNumber(args.thisv()));
 
     double d = Extract(args.thisv());
 
@@ -1222,17 +1216,17 @@ js_InitNumberClass(JSContext *cx, Handle
 
     if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Number, ctor, numberProto))
         return nullptr;
 
     return numberProto;
 }
 
 static char *
-FracNumberToCString(ThreadSafeContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
+FracNumberToCString(ExclusiveContext *cx, ToCStringBuf *cbuf, double d, int base = 10)
 {
 #ifdef DEBUG
     {
         int32_t _;
         MOZ_ASSERT(!mozilla::NumberIsInt32(d, &_));
     }
 #endif
 
@@ -1263,90 +1257,82 @@ js::NumberToCString(JSContext *cx, ToCSt
     size_t len;
     return mozilla::NumberIsInt32(d, &i)
            ? Int32ToCString(cbuf, i, &len, base)
            : FracNumberToCString(cx, cbuf, d, base);
 }
 
 template <AllowGC allowGC>
 static JSString * JS_FASTCALL
-js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base)
+js_NumberToStringWithBase(ExclusiveContext *cx, double d, int base)
 {
     ToCStringBuf cbuf;
     char *numStr;
 
     /*
      * Caller is responsible for error reporting. When called from trace,
      * returning nullptr here will cause us to fall of trace and then retry
      * from the interpreter (which will report the error).
      */
     if (base < 2 || base > 36)
         return nullptr;
 
-    JSCompartment *comp = cx->isExclusiveContext()
-                          ? cx->asExclusiveContext()->compartment()
-                          : nullptr;
+    JSCompartment *comp = cx->compartment();
 
     int32_t i;
     if (mozilla::NumberIsInt32(d, &i)) {
         if (base == 10 && StaticStrings::hasInt(i))
             return cx->staticStrings().getInt(i);
         if (unsigned(i) < unsigned(base)) {
             if (i < 10)
                 return cx->staticStrings().getInt(i);
             char16_t c = 'a' + i - 10;
             MOZ_ASSERT(StaticStrings::hasUnit(c));
             return cx->staticStrings().getUnit(c);
         }
 
-        if (comp) {
-            if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
-                return str;
-        }
+        if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
+            return str;
 
         size_t len;
         numStr = Int32ToCString(&cbuf, i, &len, base);
         MOZ_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
     } else {
-        if (comp) {
-            if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
-                return str;
-        }
+        if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
+            return str;
 
         numStr = FracNumberToCString(cx, &cbuf, d, base);
         if (!numStr) {
             js_ReportOutOfMemory(cx);
             return nullptr;
         }
         MOZ_ASSERT_IF(base == 10,
                       !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
         MOZ_ASSERT_IF(base != 10,
                       cbuf.dbuf && cbuf.dbuf == numStr);
     }
 
     JSFlatString *s = NewStringCopyZ<allowGC>(cx, numStr);
 
-    if (comp)
-        comp->dtoaCache.cache(base, d, s);
-
+    comp->dtoaCache.cache(base, d, s);
     return s;
 }
 
 template <AllowGC allowGC>
 JSString *
-js::NumberToString(ThreadSafeContext *cx, double d)
+js::NumberToString(ExclusiveContext *cx, double d)
 {
     return js_NumberToStringWithBase<allowGC>(cx, d, 10);
 }
 
 template JSString *
-js::NumberToString<CanGC>(ThreadSafeContext *cx, double d);
+js::NumberToString<CanGC>(ExclusiveContext *cx, double d);
 
 template JSString *
-js::NumberToString<NoGC>(ThreadSafeContext *cx, double d);
+js::NumberToString<NoGC>(ExclusiveContext *cx, double d);
 
 JSAtom *
 js::NumberToAtom(ExclusiveContext *cx, double d)
 {
     int32_t si;
     if (mozilla::NumberIsInt32(d, &si))
         return Int32ToAtom(cx, si);
 
@@ -1428,17 +1414,17 @@ js::NumberValueToStringBuffer(JSContext 
      * even if char16_t units are UTF-8, all chars should map to one char16_t.
      */
     MOZ_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
     return sb.append(cstr, cstrlen);
 }
 
 template <typename CharT>
 static bool
-CharsToNumber(ThreadSafeContext *cx, const CharT *chars, size_t length, double *result)
+CharsToNumber(ExclusiveContext *cx, const CharT *chars, size_t length, double *result)
 {
     if (length == 1) {
         CharT c = chars[0];
         if ('0' <= c && c <= '9')
             *result = c - '0';
         else if (unicode::IsSpace(c))
             *result = 0.0;
         else
@@ -1496,68 +1482,63 @@ CharsToNumber(ThreadSafeContext *cx, con
         *result = GenericNaN();
     else
         *result = d;
 
     return true;
 }
 
 bool
-js::StringToNumber(ThreadSafeContext *cx, JSString *str, double *result)
+js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
 {
     AutoCheckCannotGC nogc;
-    ScopedThreadSafeStringInspector inspector(str);
-    if (!inspector.ensureChars(cx, nogc))
+    JSLinearString *linearStr = str->ensureLinear(cx);
+    if (!linearStr)
         return false;
 
-    return inspector.hasLatin1Chars()
-           ? CharsToNumber(cx, inspector.latin1Chars(), str->length(), result)
-           : CharsToNumber(cx, inspector.twoByteChars(), str->length(), result);
-}
-
-bool
-js::NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out)
-{
-    MOZ_ASSERT(!v.isNumber());
-    MOZ_ASSERT(!v.isObject());
-
-    if (v.isString())
-        return StringToNumber(cx, v.toString(), out);
-    if (v.isBoolean()) {
-        *out = v.toBoolean() ? 1.0 : 0.0;
-        return true;
-    }
-    if (v.isNull()) {
-        *out = 0.0;
-        return true;
-    }
-    if (v.isSymbol()) {
-        JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_NUMBER);
-        return false;
-    }
-
-    MOZ_ASSERT(v.isUndefined());
-    *out = GenericNaN();
-    return true;
+    return linearStr->hasLatin1Chars()
+           ? CharsToNumber(cx, linearStr->latin1Chars(nogc), str->length(), result)
+           : CharsToNumber(cx, linearStr->twoByteChars(nogc), str->length(), result);
 }
 
 bool
 js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out)
 {
     MOZ_ASSERT(!v.isNumber());
     goto skip_int_double;
     for (;;) {
         if (v.isNumber()) {
             *out = v.toNumber();
             return true;
         }
 
       skip_int_double:
-        if (!v.isObject())
-            return NonObjectToNumberSlow(cx, v, out);
+        if (!v.isObject()) {
+            if (v.isString())
+                return StringToNumber(cx, v.toString(), out);
+            if (v.isBoolean()) {
+                *out = v.toBoolean() ? 1.0 : 0.0;
+                return true;
+            }
+            if (v.isNull()) {
+                *out = 0.0;
+                return true;
+            }
+            if (v.isSymbol()) {
+                if (cx->isJSContext()) {
+                    JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr,
+                                         JSMSG_SYMBOL_TO_NUMBER);
+                }
+                return false;
+            }
+
+            MOZ_ASSERT(v.isUndefined());
+            *out = GenericNaN();
+            return true;
+        }
 
         if (!cx->isJSContext())
             return false;
 
         RootedValue v2(cx, v);
         if (!ToPrimitive(cx->asJSContext(), JSTYPE_NUMBER, &v2))
             return false;
         v = v2;
@@ -1608,77 +1589,47 @@ js::ToUint64Slow(JSContext *cx, const Ha
     } else {
         if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = ToUint64(d);
     return true;
 }
 
-template <typename ContextType,
-          bool (*ToNumberSlowFn)(ContextType *, Value, double *),
-          typename ValueType>
-static bool
-ToInt32SlowImpl(ContextType *cx, const ValueType v, int32_t *out)
+JS_PUBLIC_API(bool)
+js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
 {
     MOZ_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else {
-        if (!ToNumberSlowFn(cx, v, &d))
+        if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = ToInt32(d);
     return true;
 }
 
 JS_PUBLIC_API(bool)
-js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
-{
-    return ToInt32SlowImpl<JSContext, ToNumberSlow>(cx, v, out);
-}
-
-bool
-js::NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out)
-{
-    return ToInt32SlowImpl<ThreadSafeContext, NonObjectToNumberSlow>(cx, v, out);
-}
-
-template <typename ContextType,
-          bool (*ToNumberSlowFn)(ContextType *, Value, double *),
-          typename ValueType>
-static bool
-ToUint32SlowImpl(ContextType *cx, const ValueType v, uint32_t *out)
+js::ToUint32Slow(JSContext *cx, const HandleValue v, uint32_t *out)
 {
     MOZ_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else {
-        if (!ToNumberSlowFn(cx, v, &d))
+        if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = ToUint32(d);
     return true;
 }
 
 JS_PUBLIC_API(bool)
-js::ToUint32Slow(JSContext *cx, const HandleValue v, uint32_t *out)
-{
-    return ToUint32SlowImpl<JSContext, ToNumberSlow>(cx, v, out);
-}
-
-bool
-js::NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out)
-{
-    return ToUint32SlowImpl<ThreadSafeContext, NonObjectToNumberSlow>(cx, v, out);
-}
-
-JS_PUBLIC_API(bool)
 js::ToUint16Slow(JSContext *cx, const HandleValue v, uint16_t *out)
 {
     MOZ_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
@@ -1739,17 +1690,17 @@ js::ToLengthClamped(T *cx, HandleValue v
 
 template bool
 js::ToLengthClamped<JSContext>(JSContext*, HandleValue, uint32_t*, bool*);
 template bool
 js::ToLengthClamped<ExclusiveContext>(ExclusiveContext*, HandleValue, uint32_t*, bool*);
 
 template <typename CharT>
 bool
-js_strtod(ThreadSafeContext *cx, const CharT *begin, const CharT *end, const CharT **dEnd,
+js_strtod(ExclusiveContext *cx, const CharT *begin, const CharT *end, const CharT **dEnd,
           double *d)
 {
     const CharT *s = SkipSpace(begin, end);
     size_t length = end - s;
 
     Vector<char, 32> chars(cx);
     if (!chars.growByUninitialized(length + 1))
         return false;
@@ -1788,14 +1739,14 @@ js_strtod(ThreadSafeContext *cx, const C
         *dEnd = begin;
     else
         *dEnd = s + (ep - chars.begin());
 
     return true;
 }
 
 template bool
-js_strtod(ThreadSafeContext *cx, const char16_t *begin, const char16_t *end, const char16_t **dEnd,
+js_strtod(ExclusiveContext *cx, const char16_t *begin, const char16_t *end, const char16_t **dEnd,
           double *d);
 
 template bool
-js_strtod(ThreadSafeContext *cx, const Latin1Char *begin, const Latin1Char *end,
+js_strtod(ExclusiveContext *cx, const Latin1Char *begin, const Latin1Char *end,
           const Latin1Char **dEnd, double *d);
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -44,26 +44,26 @@ class JSAtom;
 
 namespace js {
 
 /*
  * When base == 10, this function implements ToString() as specified by
  * ECMA-262-5 section 9.8.1; but note that it handles integers specially for
  * performance.  See also js::NumberToCString().
  */
-template <js::AllowGC allowGC>
+template <AllowGC allowGC>
 extern JSString *
-NumberToString(js::ThreadSafeContext *cx, double d);
+NumberToString(ExclusiveContext *cx, double d);
 
 extern JSAtom *
-NumberToAtom(js::ExclusiveContext *cx, double d);
+NumberToAtom(ExclusiveContext *cx, double d);
 
 template <AllowGC allowGC>
 extern JSFlatString *
-Int32ToString(ThreadSafeContext *cx, int32_t i);
+Int32ToString(ExclusiveContext *cx, int32_t i);
 
 extern JSAtom *
 Int32ToAtom(ExclusiveContext *cx, int32_t si);
 
 /*
  * Convert an integer or double (contained in the given value) to a string and
  * append to the given buffer.
  */
@@ -131,29 +131,29 @@ ParseDecimalNumber(const mozilla::Range<
  * base is 10 or a power of two the returned integer is the closest possible
  * double; otherwise extremely large integers may be slightly inaccurate.
  *
  * If [start, end) does not begin with a number with the specified base,
  * *dp == 0 and *endp == start upon return.
  */
 template <typename CharT>
 extern bool
-GetPrefixInteger(ThreadSafeContext *cx, const CharT *start, const CharT *end, int base,
+GetPrefixInteger(ExclusiveContext *cx, const CharT *start, const CharT *end, int base,
                  const CharT **endp, double *dp);
 
 /*
  * This is like GetPrefixInteger, but only deals with base 10, and doesn't have
  * and |endp| outparam.  It should only be used when the characters are known to
  * only contain digits.
  */
 extern bool
 GetDecimalInteger(ExclusiveContext *cx, const char16_t *start, const char16_t *end, double *dp);
 
 extern bool
-StringToNumber(ThreadSafeContext *cx, JSString *str, double *result);
+StringToNumber(ExclusiveContext *cx, JSString *str, double *result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, JS::MutableHandleValue vp)
 {
     if (vp.isNumber())
         return true;
     double d;
@@ -179,17 +179,17 @@ num_parseInt(JSContext *cx, unsigned arg
  * the appropriate sign.  The case of the "Infinity" string must match exactly.
  * If the string does not contain a number, set *dEnd to begin and return 0.0
  * in *d.
  *
  * Return false if out of memory.
  */
 template <typename CharT>
 extern bool
-js_strtod(js::ThreadSafeContext *cx, const CharT *begin, const CharT *end,
+js_strtod(js::ExclusiveContext *cx, const CharT *begin, const CharT *end,
           const CharT **dEnd, double *d);
 
 extern bool
 js_num_toString(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 js_num_valueOf(JSContext *cx, unsigned argc, js::Value *vp);
 
@@ -295,56 +295,13 @@ ToNumber(ExclusiveContext *cx, const Val
 {
     if (v.isNumber()) {
         *out = v.toNumber();
         return true;
     }
     return ToNumberSlow(cx, v, out);
 }
 
-/*
- * Thread safe variants of number conversion functions.
- */
-
-bool
-NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out);
-
-inline bool
-NonObjectToNumber(ThreadSafeContext *cx, const Value &v, double *out)
-{
-    if (v.isNumber()) {
-        *out = v.toNumber();
-        return true;
-    }
-    return NonObjectToNumberSlow(cx, v, out);
-}
-
-bool
-NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out);
-
-inline bool
-NonObjectToInt32(ThreadSafeContext *cx, const Value &v, int32_t *out)
-{
-    if (v.isInt32()) {
-        *out = v.toInt32();
-        return true;
-    }
-    return NonObjectToInt32Slow(cx, v, out);
-}
-
-bool
-NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out);
-
-MOZ_ALWAYS_INLINE bool
-NonObjectToUint32(ThreadSafeContext *cx, const Value &v, uint32_t *out)
-{
-    if (v.isInt32()) {
-        *out = uint32_t(v.toInt32());
-        return true;
-    }
-    return NonObjectToUint32Slow(cx, v, out);
-}
-
 void FIX_FPU();
 
 } /* namespace js */
 
 #endif /* jsnum_h */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4437,28 +4437,28 @@ js_strcmp(const char16_t *lhs, const cha
             return int32_t(*lhs) - int32_t(*rhs);
         if (*lhs == 0)
             return 0;
         ++lhs, ++rhs;
     }
 }
 
 UniquePtr<char[], JS::FreePolicy>
-js::DuplicateString(js::ThreadSafeContext *cx, const char *s)
+js::DuplicateString(js::ExclusiveContext *cx, const char *s)
 {
     size_t n = strlen(s) + 1;
     auto ret = cx->make_pod_array<char>(n);
     if (!ret)
         return ret;
     PodCopy(ret.get(), s, n);
     return ret;
 }
 
 UniquePtr<char16_t[], JS::FreePolicy>
-js::DuplicateString(js::ThreadSafeContext *cx, const char16_t *s)
+js::DuplicateString(js::ExclusiveContext *cx, const char16_t *s)
 {
     size_t n = js_strlen(s) + 1;
     auto ret = cx->make_pod_array<char16_t>(n);
     if (!ret)
         return ret;
     PodCopy(ret.get(), s, n);
     return ret;
 }
@@ -4477,17 +4477,17 @@ js_strchr_limit(const CharT *s, char16_t
 
 template const Latin1Char *
 js_strchr_limit(const Latin1Char *s, char16_t c, const Latin1Char *limit);
 
 template const char16_t *
 js_strchr_limit(const char16_t *s, char16_t c, const char16_t *limit);
 
 char16_t *
-js::InflateString(ThreadSafeContext *cx, const char *bytes, size_t *lengthp)
+js::InflateString(ExclusiveContext *cx, const char *bytes, size_t *lengthp)
 {
     size_t nchars;
     char16_t *chars;
     size_t nbytes = *lengthp;
 
     nchars = nbytes;
     chars = cx->pod_malloc<char16_t>(nchars + 1);
     if (!chars)
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -25,17 +25,17 @@ class JSLinearString;
 namespace js {
 
 class StringBuffer;
 
 class MutatingRopeSegmentRange;
 
 template <AllowGC allowGC>
 extern JSString *
-ConcatStrings(ThreadSafeContext *cx,
+ConcatStrings(ExclusiveContext *cx,
               typename MaybeRooted<JSString*, allowGC>::HandleType left,
               typename MaybeRooted<JSString*, allowGC>::HandleType right);
 
 // Return s advanced past any Unicode white space characters.
 template <typename CharT>
 static inline const CharT *
 SkipSpace(const CharT *s, const CharT *end)
 {
@@ -120,20 +120,20 @@ static MOZ_ALWAYS_INLINE void
 js_strncpy(char16_t *dst, const char16_t *src, size_t nelem)
 {
     return mozilla::PodCopy(dst, src, nelem);
 }
 
 namespace js {
 
 extern mozilla::UniquePtr<char[], JS::FreePolicy>
-DuplicateString(ThreadSafeContext *cx, const char *s);
+DuplicateString(ExclusiveContext *cx, const char *s);
 
 extern mozilla::UniquePtr<char16_t[], JS::FreePolicy>
-DuplicateString(ThreadSafeContext *cx, const char16_t *s);
+DuplicateString(ExclusiveContext *cx, const char16_t *s);
 
 /*
  * 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(ExclusiveContext *cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
@@ -259,17 +259,17 @@ SubstringKernel(JSContext *cx, HandleStr
 
 /*
  * Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
  * otherwise return the char16_t buffer that was malloc'ed. length is updated to
  * the length of the new string (in char16_t code units). A null char is
  * appended, but it is not included in the length.
  */
 extern char16_t *
-InflateString(ThreadSafeContext *cx, const char *bytes, size_t *length);
+InflateString(ExclusiveContext *cx, const char *bytes, size_t *length);
 
 /*
  * Inflate bytes to JS chars in an existing buffer. 'dst' must be large
  * enough for 'srclen' char16_t code units. The buffer is NOT null-terminated.
  */
 inline void
 CopyAndInflateChars(char16_t *dst, const char *src, size_t srclen)
 {
--- a/js/src/vm/CharacterEncoding.cpp
+++ b/js/src/vm/CharacterEncoding.cpp
@@ -9,17 +9,17 @@
 #include "mozilla/Range.h"
 
 #include "jscntxt.h"
 #include "jsprf.h"
 
 using namespace js;
 
 Latin1CharsZ
-JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx,
+JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ExclusiveContext *cx,
                                        const mozilla::Range<const char16_t> tbchars)
 {
     MOZ_ASSERT(cx);
     size_t len = tbchars.length();
     unsigned char *latin1 = cx->pod_malloc<unsigned char>(len + 1);
     if (!latin1)
         return Latin1CharsZ();
     for (size_t i = 0; i < len; ++i)
@@ -129,17 +129,17 @@ JS::DeflateStringToUTF8Buffer(JSFlatStri
     JS::AutoCheckCannotGC nogc;
     return src->hasLatin1Chars()
            ? ::DeflateStringToUTF8Buffer(src->latin1Chars(nogc), src->length(), dst)
            : ::DeflateStringToUTF8Buffer(src->twoByteChars(nogc), src->length(), dst);
 }
 
 template <typename CharT>
 UTF8CharsZ
-JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars)
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext *cx, const mozilla::Range<const CharT> chars)
 {
     MOZ_ASSERT(cx);
 
     /* Get required buffer size. */
     const CharT *str = chars.start().get();
     size_t len = ::GetDeflatedUTF8StringLength(str, chars.length());
 
     /* Allocate buffer. */
@@ -150,20 +150,20 @@ JS::CharsToNewUTF8CharsZ(js::ThreadSafeC
     /* Encode to UTF8. */
     ::DeflateStringToUTF8Buffer(str, chars.length(), mozilla::RangedPtr<char>(utf8, len));
     utf8[len] = '\0';
 
     return UTF8CharsZ(utf8, len);
 }
 
 template UTF8CharsZ
-JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const Latin1Char> chars);
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext *cx, const mozilla::Range<const Latin1Char> chars);
 
 template UTF8CharsZ
-JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const char16_t> chars);
+JS::CharsToNewUTF8CharsZ(js::ExclusiveContext *cx, const mozilla::Range<const char16_t> chars);
 
 static const uint32_t INVALID_UTF8 = UINT32_MAX;
 
 /*
  * Convert a utf8 character sequence into a UCS-4 character and return that
  * character.  It is assumed that the caller already checked that the sequence
  * is valid.
  */
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -17,17 +17,17 @@
 #include "gc/Marking.h"
 
 #include "jsgcinlines.h"
 
 namespace js {
 
 template <AllowGC allowGC, typename CharT>
 static MOZ_ALWAYS_INLINE JSInlineString *
-AllocateFatInlineString(ThreadSafeContext *cx, size_t len, CharT **chars)
+AllocateFatInlineString(ExclusiveContext *cx, size_t len, CharT **chars)
 {
     MOZ_ASSERT(JSFatInlineString::lengthFits<CharT>(len));
 
     if (JSInlineString::lengthFits<CharT>(len)) {
         JSInlineString *str = JSInlineString::new_<allowGC>(cx);
         if (!str)
             return nullptr;
         *chars = str->init<CharT>(len);
@@ -38,17 +38,17 @@ AllocateFatInlineString(ThreadSafeContex
     if (!str)
         return nullptr;
     *chars = str->init<CharT>(len);
     return str;
 }
 
 template <AllowGC allowGC, typename CharT>
 static MOZ_ALWAYS_INLINE JSInlineString *
-NewFatInlineString(ThreadSafeContext *cx, mozilla::Range<const CharT> chars)
+NewFatInlineString(ExclusiveContext *cx, mozilla::Range<const CharT> chars)
 {
     /*
      * Don't bother trying to find a static atom; measurement shows that not
      * many get here (for one, Atomize is catching them).
      */
 
     size_t len = chars.length();
     CharT *storage;
@@ -74,54 +74,54 @@ NewFatInlineString(ExclusiveContext *cx,
 
     JS::AutoCheckCannotGC nogc;
     mozilla::PodCopy(chars, base->chars<CharT>(nogc) + start, length);
     chars[length] = 0;
     return s;
 }
 
 static inline void
-StringWriteBarrierPost(js::ThreadSafeContext *maybecx, JSString **strp)
+StringWriteBarrierPost(js::ExclusiveContext *maybecx, JSString **strp)
 {
 }
 
 static inline void
-StringWriteBarrierPostRemove(js::ThreadSafeContext *maybecx, JSString **strp)
+StringWriteBarrierPostRemove(js::ExclusiveContext *maybecx, JSString **strp)
 {
 }
 
 } /* namespace js */
 
 MOZ_ALWAYS_INLINE bool
-JSString::validateLength(js::ThreadSafeContext *maybecx, size_t length)
+JSString::validateLength(js::ExclusiveContext *maybecx, size_t length)
 {
     if (MOZ_UNLIKELY(length > JSString::MAX_LENGTH)) {
         js_ReportAllocationOverflow(maybecx);
         return false;
     }
 
     return true;
 }
 
 MOZ_ALWAYS_INLINE void
-JSRope::init(js::ThreadSafeContext *cx, JSString *left, JSString *right, size_t length)
+JSRope::init(js::ExclusiveContext *cx, JSString *left, JSString *right, size_t length)
 {
     d.u1.length = length;
     d.u1.flags = ROPE_FLAGS;
     if (left->hasLatin1Chars() && right->hasLatin1Chars())
         d.u1.flags |= LATIN1_CHARS_BIT;
     d.s.u2.left = left;
     d.s.u3.right = right;
     js::StringWriteBarrierPost(cx, &d.s.u2.left);
     js::StringWriteBarrierPost(cx, &d.s.u3.right);
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSRope *
-JSRope::new_(js::ThreadSafeContext *cx,
+JSRope::new_(js::ExclusiveContext *cx,
              typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
              typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
              size_t length)
 {
     if (!validateLength(cx, length))
         return nullptr;
     JSRope *str = (JSRope *)js::NewGCString<allowGC>(cx);
     if (!str)
@@ -133,17 +133,17 @@ JSRope::new_(js::ThreadSafeContext *cx,
 inline void
 JSRope::markChildren(JSTracer *trc)
 {
     js::gc::MarkStringUnbarriered(trc, &d.s.u2.left, "left child");
     js::gc::MarkStringUnbarriered(trc, &d.s.u3.right, "right child");
 }
 
 MOZ_ALWAYS_INLINE void
-JSDependentString::init(js::ThreadSafeContext *cx, JSLinearString *base, size_t start,
+JSDependentString::init(js::ExclusiveContext *cx, JSLinearString *base, size_t start,
                         size_t length)
 {
     MOZ_ASSERT(!js::IsPoisonedPtr(base));
     MOZ_ASSERT(start + length <= base->length());
     d.u1.length = length;
     JS::AutoCheckCannotGC nogc;
     if (base->hasLatin1Chars()) {
         d.u1.flags = DEPENDENT_FLAGS | LATIN1_CHARS_BIT;
@@ -221,17 +221,17 @@ JSFlatString::init(const JS::Latin1Char 
 {
     d.u1.length = length;
     d.u1.flags = FLAT_BIT | LATIN1_CHARS_BIT;
     d.s.u2.nonInlineCharsLatin1 = chars;
 }
 
 template <js::AllowGC allowGC, typename CharT>
 MOZ_ALWAYS_INLINE JSFlatString *
-JSFlatString::new_(js::ThreadSafeContext *cx, const CharT *chars, size_t length)
+JSFlatString::new_(js::ExclusiveContext *cx, const CharT *chars, size_t length)
 {
     MOZ_ASSERT(chars[length] == CharT(0));
 
     if (!validateLength(cx, length))
         return nullptr;
 
     JSFlatString *str = (JSFlatString *)js::NewGCString<allowGC>(cx);
     if (!str)
@@ -253,17 +253,17 @@ JSFlatString::toPropertyName(JSContext *
     JSAtom *atom = js::AtomizeString(cx, this);
     if (!atom)
         return nullptr;
     return atom->asPropertyName();
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSInlineString *
-JSInlineString::new_(js::ThreadSafeContext *cx)
+JSInlineString::new_(js::ExclusiveContext *cx)
 {
     return (JSInlineString *)js::NewGCString<allowGC>(cx);
 }
 
 MOZ_ALWAYS_INLINE char16_t *
 JSInlineString::initTwoByte(size_t length)
 {
     MOZ_ASSERT(twoByteLengthFits(length));
@@ -324,17 +324,17 @@ template<>
 MOZ_ALWAYS_INLINE char16_t *
 JSFatInlineString::init<char16_t>(size_t length)
 {
     return initTwoByte(length);
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSFatInlineString *
-JSFatInlineString::new_(js::ThreadSafeContext *cx)
+JSFatInlineString::new_(js::ExclusiveContext *cx)
 {
     return js::NewGCFatInlineString<allowGC>(cx);
 }
 
 MOZ_ALWAYS_INLINE void
 JSExternalString::init(const char16_t *chars, size_t length, const JSStringFinalizer *fin)
 {
     MOZ_ASSERT(fin);
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -173,42 +173,42 @@ AllocChars(JSString *str, size_t length,
     *capacity = numChars - 1;
 
     JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(CharT) < UINT32_MAX);
     *chars = str->zone()->pod_malloc<CharT>(numChars);
     return *chars != nullptr;
 }
 
 bool
-JSRope::copyLatin1CharsZ(ThreadSafeContext *cx, ScopedJSFreePtr<Latin1Char> &out) const
+JSRope::copyLatin1CharsZ(ExclusiveContext *cx, ScopedJSFreePtr<Latin1Char> &out) const
 {
     return copyCharsInternal<Latin1Char>(cx, out, true);
 }
 
 bool
-JSRope::copyTwoByteCharsZ(ThreadSafeContext *cx, ScopedJSFreePtr<char16_t> &out) const
+JSRope::copyTwoByteCharsZ(ExclusiveContext *cx, ScopedJSFreePtr<char16_t> &out) const
 {
     return copyCharsInternal<char16_t>(cx, out, true);
 }
 
 bool
-JSRope::copyLatin1Chars(ThreadSafeContext *cx, ScopedJSFreePtr<Latin1Char> &out) const
+JSRope::copyLatin1Chars(ExclusiveContext *cx, ScopedJSFreePtr<Latin1Char> &out) const
 {
     return copyCharsInternal<Latin1Char>(cx, out, false);
 }
 
 bool
-JSRope::copyTwoByteChars(ThreadSafeContext *cx, ScopedJSFreePtr<char16_t> &out) const
+JSRope::copyTwoByteChars(ExclusiveContext *cx, ScopedJSFreePtr<char16_t> &out) const
 {
     return copyCharsInternal<char16_t>(cx, out, false);
 }
 
 template <typename CharT>
 bool
-JSRope::copyCharsInternal(ThreadSafeContext *cx, ScopedJSFreePtr<CharT> &out,
+JSRope::copyCharsInternal(ExclusiveContext *cx, ScopedJSFreePtr<CharT> &out,
                           bool nullTerminate) const
 {
     /*
      * Perform non-destructive post-order traversal of the rope, splatting
      * each node's characters into a contiguous buffer.
      */
 
     size_t n = length();
@@ -456,17 +456,17 @@ JSRope::flatten(ExclusiveContext *maybec
 {
     if (zone()->needsIncrementalBarrier())
         return flattenInternal<WithIncrementalBarrier>(maybecx);
     return flattenInternal<NoBarrier>(maybecx);
 }
 
 template <AllowGC allowGC>
 JSString *
-js::ConcatStrings(ThreadSafeContext *cx,
+js::ConcatStrings(ExclusiveContext *cx,
                   typename MaybeRooted<JSString*, allowGC>::HandleType left,
                   typename MaybeRooted<JSString*, allowGC>::HandleType right)
 {
     MOZ_ASSERT_IF(!left->isAtom(), cx->isInsideCurrentZone(left));
     MOZ_ASSERT_IF(!right->isAtom(), cx->isInsideCurrentZone(right));
 
     size_t leftLen = left->length();
     if (leftLen == 0)
@@ -485,50 +485,52 @@ js::ConcatStrings(ThreadSafeContext *cx,
                            ? JSFatInlineString::latin1LengthFits(wholeLength)
                            : JSFatInlineString::twoByteLengthFits(wholeLength);
     if (canUseFatInline && cx->isJSContext()) {
         JSFatInlineString *str = NewGCFatInlineString<allowGC>(cx);
         if (!str)
             return nullptr;
 
         AutoCheckCannotGC nogc;
-        ScopedThreadSafeStringInspector leftInspector(left);
-        ScopedThreadSafeStringInspector rightInspector(right);
-        if (!leftInspector.ensureChars(cx, nogc) || !rightInspector.ensureChars(cx, nogc))
+        JSLinearString *leftLinear = left->ensureLinear(cx);
+        if (!leftLinear)
+            return nullptr;
+        JSLinearString *rightLinear = right->ensureLinear(cx);
+        if (!rightLinear)
             return nullptr;
 
         if (isLatin1) {
             Latin1Char *buf = str->initLatin1(wholeLength);
-            PodCopy(buf, leftInspector.latin1Chars(), leftLen);
-            PodCopy(buf + leftLen, rightInspector.latin1Chars(), rightLen);
+            PodCopy(buf, leftLinear->latin1Chars(nogc), leftLen);
+            PodCopy(buf + leftLen, rightLinear->latin1Chars(nogc), rightLen);
             buf[wholeLength] = 0;
         } else {
             char16_t *buf = str->initTwoByte(wholeLength);
-            if (leftInspector.hasTwoByteChars())
-                PodCopy(buf, leftInspector.twoByteChars(), leftLen);
+            if (leftLinear->hasTwoByteChars())
+                PodCopy(buf, leftLinear->twoByteChars(nogc), leftLen);
             else
-                CopyAndInflateChars(buf, leftInspector.latin1Chars(), leftLen);
-            if (rightInspector.hasTwoByteChars())
-                PodCopy(buf + leftLen, rightInspector.twoByteChars(), rightLen);
+                CopyAndInflateChars(buf, leftLinear->latin1Chars(nogc), leftLen);
+            if (rightLinear->hasTwoByteChars())
+                PodCopy(buf + leftLen, rightLinear->twoByteChars(nogc), rightLen);
             else
-                CopyAndInflateChars(buf + leftLen, rightInspector.latin1Chars(), rightLen);
+                CopyAndInflateChars(buf + leftLen, rightLinear->latin1Chars(nogc), rightLen);
             buf[wholeLength] = 0;
         }
 
         return str;
     }
 
     return JSRope::new_<allowGC>(cx, left, right, wholeLength);
 }
 
 template JSString *
-js::ConcatStrings<CanGC>(ThreadSafeContext *cx, HandleString left, HandleString right);
+js::ConcatStrings<CanGC>(ExclusiveContext *cx, HandleString left, HandleString right);
 
 template JSString *
-js::ConcatStrings<NoGC>(ThreadSafeContext *cx, JSString *left, JSString *right);
+js::ConcatStrings<NoGC>(ExclusiveContext *cx, JSString *left, JSString *right);
 
 template <typename CharT>
 JSFlatString *
 JSDependentString::undependInternal(ExclusiveContext *cx)
 {
     /*
      * We destroy the base() pointer in undepend, so we need a pre-barrier. We
      * don't need a post-barrier because there aren't any outgoing pointers
@@ -616,65 +618,16 @@ JSFlatString::isIndexSlow(const CharT *s
 }
 
 template bool
 JSFlatString::isIndexSlow(const Latin1Char *s, size_t length, uint32_t *indexp);
 
 template bool
 JSFlatString::isIndexSlow(const char16_t *s, size_t length, uint32_t *indexp);
 
-bool
-ScopedThreadSafeStringInspector::ensureChars(ThreadSafeContext *cx, const AutoCheckCannotGC &nogc)
-{
-    if (state_ != Uninitialized)
-        return true;
-
-    if (cx->isExclusiveContext()) {
-        JSLinearString *linear = str_->ensureLinear(cx->asExclusiveContext());
-        if (!linear)
-            return false;
-        if (linear->hasTwoByteChars()) {
-            state_ = TwoByte;
-            twoByteChars_ = linear->twoByteChars(nogc);
-        } else {
-            state_ = Latin1;
-            latin1Chars_ = linear->latin1Chars(nogc);
-        }
-    } else {
-        if (str_->isLinear()) {
-            if (str_->hasLatin1Chars()) {
-                state_ = Latin1;
-                latin1Chars_ = str_->asLinear().latin1Chars(nogc);
-            } else {
-                state_ = TwoByte;
-                twoByteChars_ = str_->asLinear().twoByteChars(nogc);
-            }
-        } else {
-            if (str_->hasLatin1Chars()) {
-                ScopedJSFreePtr<Latin1Char> chars;
-                if (!str_->asRope().copyLatin1Chars(cx, chars))
-                    return false;
-                state_ = Latin1;
-                latin1Chars_ = chars;
-                scopedChars_ = chars.forget();
-            } else {
-                ScopedJSFreePtr<char16_t> chars;
-                if (!str_->asRope().copyTwoByteChars(cx, chars))
-                    return false;
-                state_ = TwoByte;
-                twoByteChars_ = chars;
-                scopedChars_ = chars.forget();
-            }
-        }
-    }
-
-    MOZ_ASSERT(state_ != Uninitialized);
-    return true;
-}
-
 /*
  * Set up some tools to make it easier to generate large tables. After constant
  * folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
  * Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
  * To use this, define R appropriately, then use Rn(0) (for some value of n), then
  * undefine R.
  */
 #define R2(n) R(n),  R((n) + (1 << 0)),  R((n) + (2 << 0)),  R((n) + (3 << 0))
@@ -917,17 +870,17 @@ CanStoreCharsAsLatin1(const char16_t *s,
 static bool
 CanStoreCharsAsLatin1(const Latin1Char *s, size_t length)
 {
     MOZ_CRASH("Shouldn't be called for Latin1 chars");
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE JSInlineString *
-NewFatInlineStringDeflated(ThreadSafeContext *cx, mozilla::Range<const char16_t> chars)
+NewFatInlineStringDeflated(ExclusiveContext *cx, mozilla::Range<const char16_t> chars)
 {
     size_t len = chars.length();
     Latin1Char *storage;
     JSInlineString *str = AllocateFatInlineString<allowGC>(cx, len, &storage);
     if (!str)
         return nullptr;
 
     for (size_t i = 0; i < len; i++) {
@@ -935,17 +888,17 @@ NewFatInlineStringDeflated(ThreadSafeCon
         storage[i] = Latin1Char(chars[i]);
     }
     storage[len] = '\0';
     return str;
 }
 
 template <AllowGC allowGC>
 static JSFlatString *
-NewStringDeflated(ThreadSafeContext *cx, const char16_t *s, size_t n)
+NewStringDeflated(ExclusiveContext *cx, const char16_t *s, size_t n)
 {
     if (JSFatInlineString::latin1LengthFits(n))
         return NewFatInlineStringDeflated<allowGC>(cx, mozilla::Range<const char16_t>(s, n));
 
     ScopedJSFreePtr<Latin1Char> news(cx->pod_malloc<Latin1Char>(n + 1));
     if (!news)
         return nullptr;
 
@@ -960,24 +913,24 @@ NewStringDeflated(ThreadSafeContext *cx,
         return nullptr;
 
     news.forget();
     return str;
 }
 
 template <AllowGC allowGC>
 static JSFlatString *
-NewStringDeflated(ThreadSafeContext *cx, const Latin1Char *s, size_t n)
+NewStringDeflated(ExclusiveContext *cx, const Latin1Char *s, size_t n)
 {
     MOZ_CRASH("Shouldn't be called for Latin1 chars");
 }
 
 template <AllowGC allowGC, typename CharT>
 JSFlatString *
-js::NewStringDontDeflate(ThreadSafeContext *cx, CharT *chars, size_t length)
+js::NewStringDontDeflate(ExclusiveContext *cx, CharT *chars, size_t length)
 {
     if (length == 1) {
         char16_t c = chars[0];
         if (StaticStrings::hasUnit(c)) {
             // Free |chars| because we're taking possession of it, but it's no
             // longer needed because we use the static string instead.
             js_free(chars);
             return cx->staticStrings().getUnit(c);
@@ -993,30 +946,30 @@ js::NewStringDontDeflate(ThreadSafeConte
         js_free(chars);
         return str;
     }
 
     return JSFlatString::new_<allowGC>(cx, chars, length);
 }
 
 template JSFlatString *
-js::NewStringDontDeflate<CanGC>(ThreadSafeContext *cx, char16_t *chars, size_t length);
+js::NewStringDontDeflate<CanGC>(ExclusiveContext *cx, char16_t *chars, size_t length);
 
 template JSFlatString *
-js::NewStringDontDeflate<NoGC>(ThreadSafeContext *cx, char16_t *chars, size_t length);
+js::NewStringDontDeflate<NoGC>(ExclusiveContext *cx, char16_t *chars, size_t length);
 
 template JSFlatString *
-js::NewStringDontDeflate<CanGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
+js::NewStringDontDeflate<CanGC>(ExclusiveContext *cx, Latin1Char *chars, size_t length);
 
 template JSFlatString *
-js::NewStringDontDeflate<NoGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
+js::NewStringDontDeflate<NoGC>(ExclusiveContext *cx, Latin1Char *chars, size_t length);
 
 template <AllowGC allowGC, typename CharT>
 JSFlatString *
-js::NewString(ThreadSafeContext *cx, CharT *chars, size_t length)
+js::NewString(ExclusiveContext *cx, CharT *chars, size_t length)
 {
     if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(chars, length)) {
         if (length == 1) {
             char16_t c = chars[0];
             if (StaticStrings::hasUnit(c)) {
                 js_free(chars);
                 return cx->staticStrings().getUnit(c);
             }
@@ -1030,32 +983,32 @@ js::NewString(ThreadSafeContext *cx, Cha
         js_free(chars);
         return s;
     }
 
     return NewStringDontDeflate<allowGC>(cx, chars, length);
 }
 
 template JSFlatString *
-js::NewString<CanGC>(ThreadSafeContext *cx, char16_t *chars, size_t length);
+js::NewString<CanGC>(ExclusiveContext *cx, char16_t *chars, size_t length);
 
 template JSFlatString *
-js::NewString<NoGC>(ThreadSafeContext *cx, char16_t *chars, size_t length);
+js::NewString<NoGC>(ExclusiveContext *cx, char16_t *chars, size_t length);
 
 template JSFlatString *
-js::NewString<CanGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
+js::NewString<CanGC>(ExclusiveContext *cx, Latin1Char *chars, size_t length);
 
 template JSFlatString *
-js::NewString<NoGC>(ThreadSafeContext *cx, Latin1Char *chars, size_t length);
+js::NewString<NoGC>(ExclusiveContext *cx, Latin1Char *chars, size_t length);
 
 namespace js {
 
 template <AllowGC allowGC, typename CharT>
 JSFlatString *
-NewStringCopyNDontDeflate(ThreadSafeContext *cx, const CharT *s, size_t n)
+NewStringCopyNDontDeflate(ExclusiveContext *cx, const CharT *s, size_t n)
 {
     if (JSFatInlineString::lengthFits<CharT>(n))
         return NewFatInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
 
     ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
     if (!news)
         return nullptr;
 
@@ -1066,42 +1019,42 @@ NewStringCopyNDontDeflate(ThreadSafeCont
     if (!str)
         return nullptr;
 
     news.forget();
     return str;
 }
 
 template JSFlatString *
-NewStringCopyNDontDeflate<CanGC>(ThreadSafeContext *cx, const char16_t *s, size_t n);
+NewStringCopyNDontDeflate<CanGC>(ExclusiveContext *cx, const char16_t *s, size_t n);
 
 template JSFlatString *
-NewStringCopyNDontDeflate<NoGC>(ThreadSafeContext *cx, const char16_t *s, size_t n);
+NewStringCopyNDontDeflate<NoGC>(ExclusiveContext *cx, const char16_t *s, size_t n);
 
 template JSFlatString *
-NewStringCopyNDontDeflate<CanGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
+NewStringCopyNDontDeflate<CanGC>(ExclusiveContext *cx, const Latin1Char *s, size_t n);
 
 template JSFlatString *
-NewStringCopyNDontDeflate<NoGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
+NewStringCopyNDontDeflate<NoGC>(ExclusiveContext *cx, const Latin1Char *s, size_t n);
 
 template <AllowGC allowGC, typename CharT>
 JSFlatString *
-NewStringCopyN(ThreadSafeContext *cx, const CharT *s, size_t n)
+NewStringCopyN(ExclusiveContext *cx, const CharT *s, size_t n)
 {
     if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(s, n))
         return NewStringDeflated<allowGC>(cx, s, n);
 
     return NewStringCopyNDontDeflate<allowGC>(cx, s, n);
 }
 
 template JSFlatString *
-NewStringCopyN<CanGC>(ThreadSafeContext *cx, const char16_t *s, size_t n);
+NewStringCopyN<CanGC>(ExclusiveContext *cx, const char16_t *s, size_t n);
 
 template JSFlatString *
-NewStringCopyN<NoGC>(ThreadSafeContext *cx, const char16_t *s, size_t n);
+NewStringCopyN<NoGC>(ExclusiveContext *cx, const char16_t *s, size_t n);
 
 template JSFlatString *
-NewStringCopyN<CanGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
+NewStringCopyN<CanGC>(ExclusiveContext *cx, const Latin1Char *s, size_t n);
 
 template JSFlatString *
-NewStringCopyN<NoGC>(ThreadSafeContext *cx, const Latin1Char *s, size_t n);
+NewStringCopyN<NoGC>(ExclusiveContext *cx, const Latin1Char *s, size_t n);
 
 } /* namespace js */
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -260,17 +260,17 @@ class JSString : public js::gc::TenuredC
 
     static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
 
     /*
      * Helper function to validate that a string of a given length is
      * representable by a JSString. An allocation overflow is reported if false
      * is returned.
      */
-    static inline bool validateLength(js::ThreadSafeContext *maybecx, size_t length);
+    static inline bool validateLength(js::ExclusiveContext *maybecx, size_t length);
 
     static void staticAsserts() {
         static_assert(JSString::MAX_LENGTH < UINT32_MAX, "Length must fit in 32 bits");
         static_assert(sizeof(JSString) ==
                       (offsetof(JSString, d.inlineStorageLatin1) +
                        NUM_INLINE_CHARS_LATIN1 * sizeof(char)),
                       "Inline Latin1 chars must fit in a JSString");
         static_assert(sizeof(JSString) ==
@@ -511,49 +511,49 @@ class JSString : public js::gc::TenuredC
     JSString() = delete;
     JSString(const JSString &other) = delete;
     void operator=(const JSString &other) = delete;
 };
 
 class JSRope : public JSString
 {
     template <typename CharT>
-    bool copyCharsInternal(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<CharT> &out,
+    bool copyCharsInternal(js::ExclusiveContext *cx, js::ScopedJSFreePtr<CharT> &out,
                            bool nullTerminate) const;
 
     enum UsingBarrier { WithIncrementalBarrier, NoBarrier };
 
     template<UsingBarrier b, typename CharT>
     JSFlatString *flattenInternal(js::ExclusiveContext *cx);
 
     template<UsingBarrier b>
     JSFlatString *flattenInternal(js::ExclusiveContext *cx);
 
     friend class JSString;
     JSFlatString *flatten(js::ExclusiveContext *cx);
 
-    void init(js::ThreadSafeContext *cx, JSString *left, JSString *right, size_t length);
+    void init(js::ExclusiveContext *cx, JSString *left, JSString *right, size_t length);
 
   public:
     template <js::AllowGC allowGC>
-    static inline JSRope *new_(js::ThreadSafeContext *cx,
+    static inline JSRope *new_(js::ExclusiveContext *cx,
                                typename js::MaybeRooted<JSString*, allowGC>::HandleType left,
                                typename js::MaybeRooted<JSString*, allowGC>::HandleType right,
                                size_t length);
 
-    bool copyLatin1Chars(js::ThreadSafeContext *cx,
+    bool copyLatin1Chars(js::ExclusiveContext *cx,
                          js::ScopedJSFreePtr<JS::Latin1Char> &out) const;
-    bool copyTwoByteChars(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<char16_t> &out) const;
+    bool copyTwoByteChars(js::ExclusiveContext *cx, js::ScopedJSFreePtr<char16_t> &out) const;
 
-    bool copyLatin1CharsZ(js::ThreadSafeContext *cx,
+    bool copyLatin1CharsZ(js::ExclusiveContext *cx,
                           js::ScopedJSFreePtr<JS::Latin1Char> &out) const;
-    bool copyTwoByteCharsZ(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<char16_t> &out) const;
+    bool copyTwoByteCharsZ(js::ExclusiveContext *cx, js::ScopedJSFreePtr<char16_t> &out) const;
 
     template <typename CharT>
-    bool copyChars(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<CharT> &out) const;
+    bool copyChars(js::ExclusiveContext *cx, js::ScopedJSFreePtr<CharT> &out) const;
 
     inline JSString *leftChild() const {
         MOZ_ASSERT(isRope());
         return d.s.u2.left;
     }
 
     inline JSString *rightChild() const {
         MOZ_ASSERT(isRope());
@@ -655,17 +655,17 @@ static_assert(sizeof(JSLinearString) == 
 class JSDependentString : public JSLinearString
 {
     friend class JSString;
     JSFlatString *undepend(js::ExclusiveContext *cx);
 
     template <typename CharT>
     JSFlatString *undependInternal(js::ExclusiveContext *cx);
 
-    void init(js::ThreadSafeContext *cx, JSLinearString *base, size_t start,
+    void init(js::ExclusiveContext *cx, JSLinearString *base, size_t start,
               size_t length);
 
     /* Vacuous and therefore unimplemented. */
     bool isDependent() const = delete;
     JSDependentString &asDependent() const = delete;
 
     /* The offset of this string's chars in base->chars(). */
     size_t baseOffset() const {
@@ -702,17 +702,17 @@ class JSFlatString : public JSLinearStri
     template <typename CharT>
     static bool isIndexSlow(const CharT *s, size_t length, uint32_t *indexp);
 
     void init(const char16_t *chars, size_t length);
     void init(const JS::Latin1Char *chars, size_t length);
 
   public:
     template <js::AllowGC allowGC, typename CharT>
-    static inline JSFlatString *new_(js::ThreadSafeContext *cx,
+    static inline JSFlatString *new_(js::ExclusiveContext *cx,
                                      const CharT *chars, size_t length);
 
     /*
      * Returns true if this string's characters store an unsigned 32-bit
      * integer value, initializing *indexp to that value if so.  (Thus if
      * calling isIndex returns true, js::IndexToString(cx, *indexp) will be a
      * string equal to this string.)
      */
@@ -777,17 +777,17 @@ static_assert(sizeof(JSExtensibleString)
  */
 class JSInlineString : public JSFlatString
 {
   public:
     static const size_t MAX_LENGTH_LATIN1 = NUM_INLINE_CHARS_LATIN1 - 1;
     static const size_t MAX_LENGTH_TWO_BYTE = NUM_INLINE_CHARS_TWO_BYTE - 1;
 
     template <js::AllowGC allowGC>
-    static inline JSInlineString *new_(js::ThreadSafeContext *cx);
+    static inline JSInlineString *new_(js::ExclusiveContext *cx);
 
     inline char16_t *initTwoByte(size_t length);
     inline JS::Latin1Char *initLatin1(size_t length);
 
     template <typename CharT>
     inline CharT *init(size_t length);
 
     inline void resetLength(size_t length);
@@ -844,17 +844,17 @@ class JSFatInlineString : public JSInlin
   protected: /* to fool clang into not warning this is unused */
     union {
         char   inlineStorageExtensionLatin1[INLINE_EXTENSION_CHARS_LATIN1];
         char16_t inlineStorageExtensionTwoByte[INLINE_EXTENSION_CHARS_TWO_BYTE];
     };
 
   public:
     template <js::AllowGC allowGC>
-    static inline JSFatInlineString *new_(js::ThreadSafeContext *cx);
+    static inline JSFatInlineString *new_(js::ExclusiveContext *cx);
 
     static const size_t MAX_LENGTH_LATIN1 = JSString::NUM_INLINE_CHARS_LATIN1 +
                                             INLINE_EXTENSION_CHARS_LATIN1
                                             -1 /* null terminator */;
 
     static const size_t MAX_LENGTH_TWO_BYTE = JSString::NUM_INLINE_CHARS_TWO_BYTE +
                                               INLINE_EXTENSION_CHARS_TWO_BYTE
                                               -1 /* null terminator */;
@@ -975,69 +975,16 @@ class JSAtom : public JSFlatString
 #endif
 };
 
 static_assert(sizeof(JSAtom) == sizeof(JSString),
               "string subclasses must be binary-compatible with JSString");
 
 namespace js {
 
-/*
- * Thread safe RAII wrapper for inspecting the contents of JSStrings. The
- * thread safe operations such as |getCharsNonDestructive| require allocation
- * of a char array. This allocation is not always required, such as when the
- * string is already linear. This wrapper makes dealing with this detail more
- * convenient by encapsulating the allocation logic.
- *
- * As the name suggests, this class is scoped. Return values from chars() and
- * range() may not be valid after the inspector goes out of scope.
- */
-
-class ScopedThreadSafeStringInspector
-{
-  private:
-    JSString *str_;
-    ScopedJSFreePtr<void> scopedChars_;
-    union {
-        const char16_t *twoByteChars_;
-        const JS::Latin1Char *latin1Chars_;
-    };
-    enum State { Uninitialized, Latin1, TwoByte };
-    State state_;
-
-  public:
-    explicit ScopedThreadSafeStringInspector(JSString *str)
-      : str_(str),
-        state_(Uninitialized)
-    { }
-
-    bool ensureChars(ThreadSafeContext *cx, const JS::AutoCheckCannotGC &nogc);
-
-    bool hasTwoByteChars() const { return state_ == TwoByte; }
-    bool hasLatin1Chars() const { return state_ == Latin1; }
-
-    const char16_t *twoByteChars() const {
-        MOZ_ASSERT(state_ == TwoByte);
-        return twoByteChars_;
-    }
-    const JS::Latin1Char *latin1Chars() const {
-        MOZ_ASSERT(state_ == Latin1);
-        return latin1Chars_;
-    }
-
-    mozilla::Range<const Latin1Char> latin1Range() const {
-        MOZ_ASSERT(state_ == Latin1);
-        return mozilla::Range<const Latin1Char>(latin1Chars_, str_->length());
-    }
-    mozilla::Range<const char16_t> twoByteRange() const {
-        MOZ_ASSERT(state_ == TwoByte);
-        return mozilla::Range<const char16_t>(twoByteChars_, str_->length());
-    }
-};
-
 class StaticStrings
 {
   private:
     /* Bigger chars cannot be in a length-2 string. */
     static const size_t SMALL_CHAR_LIMIT    = 128U;
     static const size_t NUM_SMALL_CHARS     = 64U;
 
     JSAtom *length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS];
@@ -1191,54 +1138,54 @@ class AutoNameVector : public AutoVector
 
 template <typename CharT>
 void
 CopyChars(CharT *dest, const JSLinearString &str);
 
 /* GC-allocate a string descriptor for the given malloc-allocated chars. */
 template <js::AllowGC allowGC, typename CharT>
 extern JSFlatString *
-NewString(js::ThreadSafeContext *cx, CharT *chars, size_t length);
+NewString(js::ExclusiveContext *cx, CharT *chars, size_t length);
 
 /* Like NewString, but doesn't try to deflate to Latin1. */
 template <js::AllowGC allowGC, typename CharT>
 extern JSFlatString *
-NewStringDontDeflate(js::ThreadSafeContext *cx, CharT *chars, size_t length);
+NewStringDontDeflate(js::ExclusiveContext *cx, CharT *chars, size_t length);
 
 extern JSLinearString *
 NewDependentString(JSContext *cx, JSString *base, size_t start, size_t length);
 
 /* Copy a counted string and GC-allocate a descriptor for it. */
 template <js::AllowGC allowGC, typename CharT>
 extern JSFlatString *
-NewStringCopyN(js::ThreadSafeContext *cx, const CharT *s, size_t n);
+NewStringCopyN(js::ExclusiveContext *cx, const CharT *s, size_t n);
 
 template <js::AllowGC allowGC>
 inline JSFlatString *
-NewStringCopyN(ThreadSafeContext *cx, const char *s, size_t n)
+NewStringCopyN(ExclusiveContext *cx, const char *s, size_t n)
 {
     return NewStringCopyN<allowGC>(cx, reinterpret_cast<const Latin1Char *>(s), n);
 }
 
 /* Like NewStringCopyN, but doesn't try to deflate to Latin1. */
 template <js::AllowGC allowGC, typename CharT>
 extern JSFlatString *
-NewStringCopyNDontDeflate(js::ThreadSafeContext *cx, const CharT *s, size_t n);
+NewStringCopyNDontDeflate(js::ExclusiveContext *cx, const CharT *s, size_t n);
 
 /* Copy a C string and GC-allocate a descriptor for it. */
 template <js::AllowGC allowGC>
 inline JSFlatString *
 NewStringCopyZ(js::ExclusiveContext *cx, const char16_t *s)
 {
     return NewStringCopyN<allowGC>(cx, s, js_strlen(s));
 }
 
 template <js::AllowGC allowGC>
 inline JSFlatString *
-NewStringCopyZ(js::ThreadSafeContext *cx, const char *s)
+NewStringCopyZ(js::ExclusiveContext *cx, const char *s)
 {
     return NewStringCopyN<allowGC>(cx, s, strlen(s));
 }
 
 } /* namespace js */
 
 // Addon IDs are interned atoms which are never destroyed. This detail is
 // not exposed outside the API.
@@ -1330,25 +1277,25 @@ template<>
 MOZ_ALWAYS_INLINE const JS::Latin1Char *
 JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
 {
     return rawLatin1Chars();
 }
 
 template <>
 MOZ_ALWAYS_INLINE bool
-JSRope::copyChars<JS::Latin1Char>(js::ThreadSafeContext *cx,
+JSRope::copyChars<JS::Latin1Char>(js::ExclusiveContext *cx,
                                   js::ScopedJSFreePtr<JS::Latin1Char> &out) const
 {
     return copyLatin1Chars(cx, out);
 }
 
 template <>
 MOZ_ALWAYS_INLINE bool
-JSRope::copyChars<char16_t>(js::ThreadSafeContext *cx, js::ScopedJSFreePtr<char16_t> &out) const
+JSRope::copyChars<char16_t>(js::ExclusiveContext *cx, js::ScopedJSFreePtr<char16_t> &out) const
 {
     return copyTwoByteChars(cx, out);
 }
 
 template<>
 MOZ_ALWAYS_INLINE bool
 JSInlineString::lengthFits<JS::Latin1Char>(size_t length)
 {