Bug 1439712 - Improve JSString::ensureLinear error reporting, r=jonco
authorSteve Fink <sfink@mozilla.com>
Tue, 20 Feb 2018 12:41:04 -0800
changeset 467951 321ec4ba2ea3421c45612c2bcdf8a8e0696b1b77
parent 467889 fb5f1d08489f41235639568b5c53ab65deb752ef
child 467952 d56f8af6e3ab03e12fc22fd0f4b6003d50e8218e
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1439712
milestone61.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 1439712 - Improve JSString::ensureLinear error reporting, r=jonco
js/src/ctypes/CTypes.cpp
js/src/ctypes/CTypes.h
js/src/ctypes/Library.cpp
js/src/jit/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/vm/StringType.cpp
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -1009,22 +1009,22 @@ BuildCStyleTypeSource(JSContext* cx, JSO
 {
   RootedObject typeObj(cx, typeObj_);
 
   MOZ_ASSERT(CType::IsCType(typeObj));
 
   switch (CType::GetTypeCode(typeObj)) {
 #define BUILD_SOURCE(name, fromType, ffiType)                                  \
   case TYPE_##name:                                                            \
-    AppendString(source, #name);                                               \
+    AppendString(cx, source, #name);                                           \
     break;
   CTYPES_FOR_EACH_TYPE(BUILD_SOURCE)
 #undef BUILD_SOURCE
   case TYPE_void_t:
-    AppendString(source, "void");
+    AppendString(cx, source, "void");
     break;
   case TYPE_pointer: {
     unsigned ptrCount = 0;
     TypeCode type;
     RootedObject baseTypeObj(cx, typeObj);
     do {
       baseTypeObj = PointerType::GetBaseType(baseTypeObj);
       ptrCount++;
@@ -1036,18 +1036,18 @@ BuildCStyleTypeSource(JSContext* cx, JSO
       break;
     }
     BuildCStyleTypeSource(cx, baseTypeObj, source);
     AppendChars(source, '*', ptrCount);
     break;
   }
   case TYPE_struct: {
     RootedString name(cx, CType::GetName(cx, typeObj));
-    AppendString(source, "struct ");
-    AppendString(source, name);
+    AppendString(cx, source, "struct ");
+    AppendString(cx, source, name);
     break;
   }
   case TYPE_function:
     BuildCStyleFunctionTypeSource(cx, typeObj, nullptr, 0, source);
     break;
   case TYPE_array:
     MOZ_CRASH("TYPE_array shouldn't appear in function type");
   }
@@ -1057,38 +1057,38 @@ static void
 BuildCStyleFunctionTypeSource(JSContext* cx, HandleObject typeObj,
                               HandleString nameStr, unsigned ptrCount,
                               AutoString& source)
 {
   MOZ_ASSERT(CType::IsCType(typeObj));
 
   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
   BuildCStyleTypeSource(cx, fninfo->mReturnType, source);
-  AppendString(source, " ");
+  AppendString(cx, source, " ");
   if (nameStr) {
     MOZ_ASSERT(ptrCount == 0);
-    AppendString(source, nameStr);
+    AppendString(cx, source, nameStr);
   } else if (ptrCount) {
-    AppendString(source, "(");
+    AppendString(cx, source, "(");
     AppendChars(source, '*', ptrCount);
-    AppendString(source, ")");
-  }
-  AppendString(source, "(");
+    AppendString(cx, source, ")");
+  }
+  AppendString(cx, source, "(");
   if (fninfo->mArgTypes.length() > 0) {
     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
       BuildCStyleTypeSource(cx, fninfo->mArgTypes[i], source);
       if (i != fninfo->mArgTypes.length() - 1 || fninfo->mIsVariadic) {
-          AppendString(source, ", ");
+          AppendString(cx, source, ", ");
       }
     }
     if (fninfo->mIsVariadic) {
-      AppendString(source, "...");
+      AppendString(cx, source, "...");
     }
   }
-  AppendString(source, ")");
+  AppendString(cx, source, ")");
 }
 
 static void
 BuildFunctionTypeSource(JSContext* cx, HandleObject funObj, AutoString& source)
 {
   MOZ_ASSERT(CData::IsCData(funObj) || CType::IsCType(funObj));
 
   if (CData::IsCData(funObj)) {
@@ -1103,20 +1103,20 @@ BuildFunctionTypeSource(JSContext* cx, H
       return;
     }
   }
 
   RootedValue funVal(cx, ObjectValue(*funObj));
   RootedString funcStr(cx, JS_ValueToSource(cx, funVal));
   if (!funcStr) {
     JS_ClearPendingException(cx);
-    AppendString(source, "<<error converting function to string>>");
+    AppendString(cx, source, "<<error converting function to string>>");
     return;
   }
-  AppendString(source, funcStr);
+  AppendString(cx, source, funcStr);
 }
 
 enum class ConversionType {
   Argument = 0,
   Construct,
   Finalizer,
   Return,
   Setter
@@ -1126,32 +1126,32 @@ static void
 BuildConversionPosition(JSContext* cx, ConversionType convType,
                         HandleObject funObj, unsigned argIndex,
                         AutoString& source)
 {
   switch (convType) {
   case ConversionType::Argument: {
     MOZ_ASSERT(funObj);
 
-    AppendString(source, " at argument ");
+    AppendString(cx, source, " at argument ");
     AppendUInt(source, argIndex + 1);
-    AppendString(source, " of ");
+    AppendString(cx, source, " of ");
     BuildFunctionTypeSource(cx, funObj, source);
     break;
   }
   case ConversionType::Finalizer:
     MOZ_ASSERT(funObj);
 
-    AppendString(source, " at argument 1 of ");
+    AppendString(cx, source, " at argument 1 of ");
     BuildFunctionTypeSource(cx, funObj, source);
     break;
   case ConversionType::Return:
     MOZ_ASSERT(funObj);
 
-    AppendString(source, " at the return value of ");
+    AppendString(cx, source, " at the return value of ");
     BuildFunctionTypeSource(cx, funObj, source);
     break;
   default:
     MOZ_ASSERT(!funObj);
     break;
   }
 }
 
@@ -3984,79 +3984,79 @@ BuildTypeName(JSContext* cx, JSObject* t
   // of the rules for building C type declarations can be found at:
   // http://unixwiz.net/techtips/reading-cdecl.html
   TypeCode prevGrouping = CType::GetTypeCode(typeObj), currentGrouping;
   while (true) {
     currentGrouping = CType::GetTypeCode(typeObj);
     switch (currentGrouping) {
     case TYPE_pointer: {
       // Pointer types go on the left.
-      PrependString(result, "*");
+      PrependString(cx, result, "*");
 
       typeObj = PointerType::GetBaseType(typeObj);
       prevGrouping = currentGrouping;
       continue;
     }
     case TYPE_array: {
       if (prevGrouping == TYPE_pointer) {
         // Outer type is pointer, inner type is array. Grouping is required.
-        PrependString(result, "(");
-        AppendString(result, ")");
+        PrependString(cx, result, "(");
+        AppendString(cx, result, ")");
       }
 
       // Array types go on the right.
-      AppendString(result, "[");
+      AppendString(cx, result, "[");
       size_t length;
       if (ArrayType::GetSafeLength(typeObj, &length))
         IntegerToString(length, 10, result);
 
-      AppendString(result, "]");
+      AppendString(cx, result, "]");
 
       typeObj = ArrayType::GetBaseType(typeObj);
       prevGrouping = currentGrouping;
       continue;
     }
     case TYPE_function: {
       FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
 
       // Add in the calling convention, if it's not cdecl.
       // There's no trailing or leading space needed here, as none of the
       // modifiers can produce a string beginning with an identifier ---
       // except for TYPE_function itself, which is fine because functions
       // can't return functions.
       ABICode abi = GetABICode(fninfo->mABI);
       if (abi == ABI_STDCALL)
-        PrependString(result, "__stdcall");
+        PrependString(cx, result, "__stdcall");
       else if (abi == ABI_THISCALL)
-        PrependString(result, "__thiscall");
+        PrependString(cx, result, "__thiscall");
       else if (abi == ABI_WINAPI)
-        PrependString(result, "WINAPI");
+        PrependString(cx, result, "WINAPI");
 
       // Function application binds more tightly than dereferencing, so
       // wrap pointer types in parens. Functions can't return functions
       // (only pointers to them), and arrays can't hold functions
       // (similarly), so we don't need to address those cases.
       if (prevGrouping == TYPE_pointer) {
-        PrependString(result, "(");
-        AppendString(result, ")");
+        PrependString(cx, result, "(");
+        AppendString(cx, result, ")");
       }
 
       // Argument list goes on the right.
-      AppendString(result, "(");
+      AppendString(cx, result, "(");
       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
         RootedObject argType(cx, fninfo->mArgTypes[i]);
         JSString* argName = CType::GetName(cx, argType);
-        AppendString(result, argName);
+        AppendString(cx, result, argName);
         if (i != fninfo->mArgTypes.length() - 1 ||
             fninfo->mIsVariadic)
-          AppendString(result, ", ");
+          AppendString(cx, result, ", ");
       }
       if (fninfo->mIsVariadic)
-        AppendString(result, "...");
-      AppendString(result, ")");
+        AppendString(cx, result, "...");
+      AppendString(cx, result, ")");
 
       // Set 'typeObj' to the return type, and let the loop process it.
       // 'prevGrouping' doesn't matter here, because functions cannot return
       // arrays -- thus the parenthetical rules don't get tickled.
       typeObj = fninfo->mReturnType;
       continue;
     }
     default:
@@ -4064,21 +4064,21 @@ BuildTypeName(JSContext* cx, JSObject* t
       break;
     }
     break;
   }
 
   // If prepending the base type name directly would splice two
   // identifiers, insert a space.
   if (IsAsciiAlpha(result[0]) || result[0] == '_')
-    PrependString(result, " ");
+    PrependString(cx, result, " ");
 
   // Stick the base type and derived type parts together.
   JSString* baseName = CType::GetName(cx, typeObj);
-  PrependString(result, baseName);
+  PrependString(cx, result, baseName);
   return NewUCString(cx, result);
 }
 
 // Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
 // would construct the same CType. If 'makeShort' is true, assume that any
 // StructType 't' is bound to an in-scope variable of name 't.name', and use
 // that variable in place of generating a string to construct the type 't'.
 // (This means the type comparison function CType::TypesEqual will return true
@@ -4094,136 +4094,136 @@ BuildTypeSource(JSContext* cx,
 
   // Walk the types, building up the toSource() string.
   switch (CType::GetTypeCode(typeObj)) {
   case TYPE_void_t:
 #define CASE_FOR_TYPE(name, type, ffiType)  case TYPE_##name:
   CTYPES_FOR_EACH_TYPE(CASE_FOR_TYPE)
 #undef CASE_FOR_TYPE
   {
-    AppendString(result, "ctypes.");
+    AppendString(cx, result, "ctypes.");
     JSString* nameStr = CType::GetName(cx, typeObj);
-    AppendString(result, nameStr);
+    AppendString(cx, result, nameStr);
     break;
   }
   case TYPE_pointer: {
     RootedObject baseType(cx, PointerType::GetBaseType(typeObj));
 
     // Specialcase ctypes.voidptr_t.
     if (CType::GetTypeCode(baseType) == TYPE_void_t) {
-      AppendString(result, "ctypes.voidptr_t");
+      AppendString(cx, result, "ctypes.voidptr_t");
       break;
     }
 
     // Recursively build the source string, and append '.ptr'.
     BuildTypeSource(cx, baseType, makeShort, result);
-    AppendString(result, ".ptr");
+    AppendString(cx, result, ".ptr");
     break;
   }
   case TYPE_function: {
     FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
 
-    AppendString(result, "ctypes.FunctionType(");
+    AppendString(cx, result, "ctypes.FunctionType(");
 
     switch (GetABICode(fninfo->mABI)) {
     case ABI_DEFAULT:
-      AppendString(result, "ctypes.default_abi, ");
+      AppendString(cx, result, "ctypes.default_abi, ");
       break;
     case ABI_STDCALL:
-      AppendString(result, "ctypes.stdcall_abi, ");
+      AppendString(cx, result, "ctypes.stdcall_abi, ");
       break;
     case ABI_THISCALL:
-      AppendString(result, "ctypes.thiscall_abi, ");
+      AppendString(cx, result, "ctypes.thiscall_abi, ");
       break;
     case ABI_WINAPI:
-      AppendString(result, "ctypes.winapi_abi, ");
+      AppendString(cx, result, "ctypes.winapi_abi, ");
       break;
     case INVALID_ABI:
       MOZ_CRASH("invalid abi");
     }
 
     // Recursively build the source string describing the function return and
     // argument types.
     BuildTypeSource(cx, fninfo->mReturnType, true, result);
 
     if (fninfo->mArgTypes.length() > 0) {
-      AppendString(result, ", [");
+      AppendString(cx, result, ", [");
       for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
         BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
         if (i != fninfo->mArgTypes.length() - 1 ||
             fninfo->mIsVariadic)
-          AppendString(result, ", ");
+          AppendString(cx, result, ", ");
       }
       if (fninfo->mIsVariadic)
-        AppendString(result, "\"...\"");
-      AppendString(result, "]");
+        AppendString(cx, result, "\"...\"");
+      AppendString(cx, result, "]");
     }
 
-    AppendString(result, ")");
+    AppendString(cx, result, ")");
     break;
   }
   case TYPE_array: {
     // Recursively build the source string, and append '.array(n)',
     // where n is the array length, or the empty string if the array length
     // is undefined.
     JSObject* baseType = ArrayType::GetBaseType(typeObj);
     BuildTypeSource(cx, baseType, makeShort, result);
-    AppendString(result, ".array(");
+    AppendString(cx, result, ".array(");
 
     size_t length;
     if (ArrayType::GetSafeLength(typeObj, &length))
       IntegerToString(length, 10, result);
 
-    AppendString(result, ")");
+    AppendString(cx, result, ")");
     break;
   }
   case TYPE_struct: {
     JSString* name = CType::GetName(cx, typeObj);
 
     if (makeShort) {
       // Shorten the type declaration by assuming that StructType 't' is bound
       // to an in-scope variable of name 't.name'.
-      AppendString(result, name);
+      AppendString(cx, result, name);
       break;
     }
 
     // Write the full struct declaration.
-    AppendString(result, "ctypes.StructType(\"");
-    AppendString(result, name);
-    AppendString(result, "\"");
+    AppendString(cx, result, "ctypes.StructType(\"");
+    AppendString(cx, result, name);
+    AppendString(cx, result, "\"");
 
     // If it's an opaque struct, we're done.
     if (!CType::IsSizeDefined(typeObj)) {
-      AppendString(result, ")");
+      AppendString(cx, result, ")");
       break;
     }
 
-    AppendString(result, ", [");
+    AppendString(cx, result, ", [");
 
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
     Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
     if (!fieldsArray.resize(length))
       break;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
       fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
-      AppendString(result, "{ \"");
-      AppendString(result, entry->key());
-      AppendString(result, "\": ");
+      AppendString(cx, result, "{ \"");
+      AppendString(cx, result, entry->key());
+      AppendString(cx, result, "\": ");
       BuildTypeSource(cx, entry->value().mType, true, result);
-      AppendString(result, " }");
+      AppendString(cx, result, " }");
       if (i != length - 1)
-        AppendString(result, ", ");
+        AppendString(cx, result, ", ");
     }
 
-    AppendString(result, "])");
+    AppendString(cx, result, "])");
     break;
   }
   }
 }
 
 // Given a CData object of CType 'typeObj' with binary value 'data', generate a
 // string 'result' such that 'eval(result)' would construct a CData object with
 // the same CType and containing the same binary value. This assumes that any
@@ -4240,37 +4240,37 @@ BuildDataSource(JSContext* cx,
                 void* data,
                 bool isImplicit,
                 AutoString& result)
 {
   TypeCode type = CType::GetTypeCode(typeObj);
   switch (type) {
   case TYPE_bool:
     if (*static_cast<bool*>(data))
-      AppendString(result, "true");
+      AppendString(cx, result, "true");
     else
-      AppendString(result, "false");
+      AppendString(cx, result, "false");
     break;
 #define INTEGRAL_CASE(name, type, ffiType)                                     \
   case TYPE_##name:                                                            \
     /* Serialize as a primitive decimal integer. */                            \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
     break;
   CTYPES_FOR_EACH_INT_TYPE(INTEGRAL_CASE)
 #undef INTEGRAL_CASE
 #define WRAPPED_INT_CASE(name, type, ffiType)                                  \
   case TYPE_##name:                                                            \
     /* Serialize as a wrapped decimal integer. */                              \
     if (!numeric_limits<type>::is_signed)                                      \
-      AppendString(result, "ctypes.UInt64(\"");                                \
+      AppendString(cx, result, "ctypes.UInt64(\"");                                \
     else                                                                       \
-      AppendString(result, "ctypes.Int64(\"");                                 \
+      AppendString(cx, result, "ctypes.Int64(\"");                                 \
                                                                                \
     IntegerToString(*static_cast<type*>(data), 10, result);                    \
-    AppendString(result, "\")");                                               \
+    AppendString(cx, result, "\")");                                               \
     break;
   CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
 #undef WRAPPED_INT_CASE
 #define FLOAT_CASE(name, type, ffiType)                                        \
   case TYPE_##name: {                                                          \
     /* Serialize as a primitive double. */                                     \
     double fp = *static_cast<type*>(data);                                     \
     ToCStringBuf cbuf;                                                         \
@@ -4297,64 +4297,64 @@ BuildDataSource(JSContext* cx,
       return false;
 
     // Escape characters, and quote as necessary.
     RootedValue valStr(cx, StringValue(str));
     JSString* src = JS_ValueToSource(cx, valStr);
     if (!src)
       return false;
 
-    AppendString(result, src);
+    AppendString(cx, result, src);
     break;
   }
   case TYPE_pointer:
   case TYPE_function: {
     if (isImplicit) {
       // The result must be able to ImplicitConvert successfully.
       // Wrap in a type constructor, then serialize for ExplicitConvert.
       BuildTypeSource(cx, typeObj, true, result);
-      AppendString(result, "(");
+      AppendString(cx, result, "(");
     }
 
     // Serialize the pointer value as a wrapped hexadecimal integer.
     uintptr_t ptr = *static_cast<uintptr_t*>(data);
-    AppendString(result, "ctypes.UInt64(\"0x");
+    AppendString(cx, result, "ctypes.UInt64(\"0x");
     IntegerToString(ptr, 16, result);
-    AppendString(result, "\")");
+    AppendString(cx, result, "\")");
 
     if (isImplicit)
-      AppendString(result, ")");
+      AppendString(cx, result, ")");
 
     break;
   }
   case TYPE_array: {
     // Serialize each element of the array recursively. Each element must
     // be able to ImplicitConvert successfully.
     RootedObject baseType(cx, ArrayType::GetBaseType(typeObj));
-    AppendString(result, "[");
+    AppendString(cx, result, "[");
 
     size_t length = ArrayType::GetLength(typeObj);
     size_t elementSize = CType::GetSize(baseType);
     for (size_t i = 0; i < length; ++i) {
       char* element = static_cast<char*>(data) + elementSize * i;
       if (!BuildDataSource(cx, baseType, element, true, result))
         return false;
 
       if (i + 1 < length)
-        AppendString(result, ", ");
+        AppendString(cx, result, ", ");
     }
-    AppendString(result, "]");
+    AppendString(cx, result, "]");
     break;
   }
   case TYPE_struct: {
     if (isImplicit) {
       // The result must be able to ImplicitConvert successfully.
       // Serialize the data as an object with properties, rather than
       // a sequence of arguments to the StructType constructor.
-      AppendString(result, "{");
+      AppendString(cx, result, "{");
     }
 
     // Serialize each field of the struct recursively. Each field must
     // be able to ImplicitConvert successfully.
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
     Vector<const FieldInfoHash::Entry*, 64, SystemAllocPolicy> fieldsArray;
     if (!fieldsArray.resize(length))
@@ -4362,32 +4362,32 @@ BuildDataSource(JSContext* cx,
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
       fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
 
       if (isImplicit) {
-        AppendString(result, "\"");
-        AppendString(result, entry->key());
-        AppendString(result, "\": ");
+        AppendString(cx, result, "\"");
+        AppendString(cx, result, entry->key());
+        AppendString(cx, result, "\": ");
       }
 
       char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
       RootedObject entryType(cx, entry->value().mType);
       if (!BuildDataSource(cx, entryType, fieldData, true, result))
         return false;
 
       if (i + 1 != length)
-        AppendString(result, ", ");
+        AppendString(cx, result, ", ");
     }
 
     if (isImplicit)
-      AppendString(result, "}");
+      AppendString(cx, result, "}");
 
     break;
   }
   case TYPE_void_t:
     MOZ_CRASH("invalid type");
   }
 
   return true;
@@ -4992,18 +4992,18 @@ CType::ToString(JSContext* cx, unsigned 
                                  InformalValueTypeName(args.thisv()));
   }
 
   // Create the appropriate string depending on whether we're sCTypeClass or
   // sCTypeProtoClass.
   JSString* result;
   if (CType::IsCType(obj)) {
     AutoString type;
-    AppendString(type, "type ");
-    AppendString(type, GetName(cx, obj));
+    AppendString(cx, type, "type ");
+    AppendString(cx, type, GetName(cx, obj));
     result = NewUCString(cx, type);
   }
   else {
     result = JS_NewStringCopyZ(cx, "[CType proto object]");
   }
   if (!result)
     return false;
 
@@ -6800,52 +6800,53 @@ PrepareCIF(JSContext* cx,
     return false;
   default:
     JS_ReportErrorASCII(cx, "Unknown libffi error");
     return false;
   }
 }
 
 void
-FunctionType::BuildSymbolName(JSString* name,
+FunctionType::BuildSymbolName(JSContext* cx,
+                              JSString* name,
                               JSObject* typeObj,
                               AutoCString& result)
 {
   FunctionInfo* fninfo = GetFunctionInfo(typeObj);
 
   switch (GetABICode(fninfo->mABI)) {
   case ABI_DEFAULT:
   case ABI_THISCALL:
   case ABI_WINAPI:
     // For cdecl or WINAPI functions, no mangling is necessary.
-    AppendString(result, name);
+    AppendString(cx, result, name);
     break;
 
   case ABI_STDCALL: {
 #if (defined(_WIN32) && !defined(_WIN64)) || defined(_OS2)
     // On WIN32, stdcall functions look like:
     //   _foo@40
     // where 'foo' is the function name, and '40' is the aligned size of the
     // arguments.
-    AppendString(result, "_");
-    AppendString(result, name);
-    AppendString(result, "@");
+    AppendString(cx, result, "_");
+    AppendString(cx, result, name);
+    AppendString(cx, result, "@");
 
     // Compute the suffix by aligning each argument to sizeof(ffi_arg).
     size_t size = 0;
     for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
       JSObject* argType = fninfo->mArgTypes[i];
       size += Align(CType::GetSize(argType), sizeof(ffi_arg));
     }
 
     IntegerToString(size, 10, result);
 #elif defined(_WIN64)
     // On Win64, stdcall is an alias to the default ABI for compatibility, so no
     // mangling is done.
-    AppendString(result, name);
+    AppendString(cx, result, name);
 #endif
     break;
   }
 
   case INVALID_ABI:
     MOZ_CRASH("invalid abi");
   }
 }
@@ -8054,21 +8055,21 @@ CData::GetSourceString(JSContext* cx, Ha
   // Walk the types, building up the toSource() string.
   // First, we build up the type expression:
   // 't.ptr' for pointers;
   // 't.array([n])' for arrays;
   // 'n' for structs, where n = t.name, the struct's name. (We assume this is
   // bound to a variable in the current scope.)
   AutoString source;
   BuildTypeSource(cx, typeObj, true, source);
-  AppendString(source, "(");
+  AppendString(cx, source, "(");
   if (!BuildDataSource(cx, typeObj, data, false, source))
     return nullptr;
 
-  AppendString(source, ")");
+  AppendString(cx, source, ")");
 
   return NewUCString(cx, source);
 }
 
 bool
 CData::ToSource(JSContext* cx, unsigned argc, Value* vp)
 {
   CallArgs args = CallArgsFromVp(argc, vp);
@@ -8138,37 +8139,37 @@ CDataFinalizer::Methods::ToSource(JSCont
   } else {
     RootedObject objType(cx, CDataFinalizer::GetCType(cx, objThis));
     if (!objType) {
       JS_ReportErrorASCII(cx, "CDataFinalizer has no type");
       return false;
     }
 
     AutoString source;
-    AppendString(source, "ctypes.CDataFinalizer(");
+    AppendString(cx, source, "ctypes.CDataFinalizer(");
     JSString* srcValue = CData::GetSourceString(cx, objType, p->cargs);
     if (!srcValue) {
       return false;
     }
-    AppendString(source, srcValue);
-    AppendString(source, ", ");
+    AppendString(cx, source, srcValue);
+    AppendString(cx, source, ", ");
     Value valCodePtrType = JS_GetReservedSlot(objThis,
                                               SLOT_DATAFINALIZER_CODETYPE);
     if (valCodePtrType.isPrimitive()) {
       return false;
     }
 
     RootedObject typeObj(cx, valCodePtrType.toObjectOrNull());
     JSString* srcDispose = CData::GetSourceString(cx, typeObj, &(p->code));
     if (!srcDispose) {
       return false;
     }
 
-    AppendString(source, srcDispose);
-    AppendString(source, ")");
+    AppendString(cx, source, srcDispose);
+    AppendString(cx, source, ")");
     strMessage = NewUCString(cx, source);
   }
 
   if (!strMessage) {
     // This is a memory issue, no error message
     return false;
   }
 
@@ -8763,23 +8764,23 @@ Int64Base::ToSource(JSContext* cx,
       return ArgumentLengthError(cx, "UInt64.prototype.toSource", "no", "s");
     }
     return ArgumentLengthError(cx, "Int64.prototype.toSource", "no", "s");
   }
 
   // Return a decimal string suitable for constructing the number.
   AutoString source;
   if (isUnsigned) {
-    AppendString(source, "ctypes.UInt64(\"");
+    AppendString(cx, source, "ctypes.UInt64(\"");
     IntegerToString(GetInt(obj), 10, source);
   } else {
-    AppendString(source, "ctypes.Int64(\"");
+    AppendString(cx, source, "ctypes.Int64(\"");
     IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
   }
-  AppendString(source, "\")");
+  AppendString(cx, source, "\")");
 
   JSString* result = NewUCString(cx, source);
   if (!result)
     return false;
 
   args.rval().setString(result);
   return true;
 }
--- a/js/src/ctypes/CTypes.h
+++ b/js/src/ctypes/CTypes.h
@@ -30,17 +30,17 @@ namespace ctypes {
 typedef Vector<char16_t,  0, SystemAllocPolicy> String;
 typedef Vector<char16_t, 64, SystemAllocPolicy> AutoString;
 typedef Vector<char,      0, SystemAllocPolicy> CString;
 typedef Vector<char,     64, SystemAllocPolicy> AutoCString;
 
 // Convenience functions to append, insert, and compare Strings.
 template <class T, size_t N, class AP, size_t ArrayLength>
 void
-AppendString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
+AppendString(JSContext* cx, mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
 {
   // Don't include the trailing '\0'.
   size_t alen = ArrayLength - 1;
   size_t vlen = v.length();
   if (!v.resize(vlen + alen))
     return;
 
   for (size_t i = 0; i < alen; ++i)
@@ -70,51 +70,51 @@ AppendUInt(mozilla::Vector<T, N, AP>& v,
     return;
 
   for (size_t i = 0; i < alen; ++i)
     v[i + vlen] = array[i];
 }
 
 template <class T, size_t N, size_t M, class AP>
 void
-AppendString(mozilla::Vector<T, N, AP>& v, mozilla::Vector<T, M, AP>& w)
+AppendString(JSContext* cx, mozilla::Vector<T, N, AP>& v, mozilla::Vector<T, M, AP>& w)
 {
   if (!v.append(w.begin(), w.length()))
     return;
 }
 
 template <size_t N, class AP>
 void
-AppendString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
+AppendString(JSContext* cx, mozilla::Vector<char16_t, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
-  JSLinearString* linear = str->ensureLinear(nullptr);
+  JSLinearString* linear = str->ensureLinear(cx);
   if (!linear)
     return;
   JS::AutoCheckCannotGC nogc;
   if (linear->hasLatin1Chars()) {
     if (!v.append(linear->latin1Chars(nogc), linear->length()))
       return;
   } else {
     if (!v.append(linear->twoByteChars(nogc), linear->length()))
       return;
   }
 }
 
 template <size_t N, class AP>
 void
-AppendString(mozilla::Vector<char, N, AP>& v, JSString* str)
+AppendString(JSContext* cx, mozilla::Vector<char, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
   size_t vlen = v.length();
   size_t alen = str->length();
   if (!v.resize(vlen + alen))
     return;
 
-  JSLinearString* linear = str->ensureLinear(nullptr);
+  JSLinearString* linear = str->ensureLinear(cx);
   if (!linear)
     return;
 
   JS::AutoCheckCannotGC nogc;
   if (linear->hasLatin1Chars()) {
     const Latin1Char* chars = linear->latin1Chars(nogc);
     for (size_t i = 0; i < alen; ++i)
       v[i + vlen] = char(chars[i]);
@@ -122,17 +122,17 @@ AppendString(mozilla::Vector<char, N, AP
     const char16_t* chars = linear->twoByteChars(nogc);
     for (size_t i = 0; i < alen; ++i)
       v[i + vlen] = char(chars[i]);
   }
 }
 
 template <class T, size_t N, class AP, size_t ArrayLength>
 void
-PrependString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
+PrependString(JSContext* cx, mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
 {
   // Don't include the trailing '\0'.
   size_t alen = ArrayLength - 1;
   size_t vlen = v.length();
   if (!v.resize(vlen + alen))
     return;
 
   // Move vector data forward. This is safe since we've already resized.
@@ -140,25 +140,25 @@ PrependString(mozilla::Vector<T, N, AP>&
 
   // Copy data to insert.
   for (size_t i = 0; i < alen; ++i)
     v[i] = array[i];
 }
 
 template <size_t N, class AP>
 void
-PrependString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
+PrependString(JSContext* cx, mozilla::Vector<char16_t, N, AP>& v, JSString* str)
 {
   MOZ_ASSERT(str);
   size_t vlen = v.length();
   size_t alen = str->length();
   if (!v.resize(vlen + alen))
     return;
 
-  JSLinearString* linear = str->ensureLinear(nullptr);
+  JSLinearString* linear = str->ensureLinear(cx);
   if (!linear)
     return;
 
   // Move vector data forward. This is safe since we've already resized.
   memmove(v.begin() + alen, v.begin(), vlen * sizeof(char16_t));
 
   // Copy data to insert.
   JS::AutoCheckCannotGC nogc;
@@ -497,17 +497,17 @@ namespace StructType {
 namespace FunctionType {
   JSObject* CreateInternal(JSContext* cx, HandleValue abi, HandleValue rtype,
     const HandleValueArray& args);
 
   JSObject* ConstructWithObject(JSContext* cx, JSObject* typeObj,
     JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
 
   FunctionInfo* GetFunctionInfo(JSObject* obj);
-  void BuildSymbolName(JSString* name, JSObject* typeObj,
+  void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
     AutoCString& result);
 } // namespace FunctionType
 
 namespace CClosure {
   JSObject* Create(JSContext* cx, HandleObject typeObj, HandleObject fnObj,
     HandleObject thisObj, HandleValue errVal, PRFuncPtr* fnptr);
 } // namespace CClosure
 
--- a/js/src/ctypes/Library.cpp
+++ b/js/src/ctypes/Library.cpp
@@ -67,19 +67,19 @@ Library::Name(JSContext* cx, unsigned ar
   if (arg.isString()) {
     str = arg.toString();
   } else {
     JS_ReportErrorASCII(cx, "name argument must be a string");
     return false;
   }
 
   AutoString resultString;
-  AppendString(resultString, DLL_PREFIX);
-  AppendString(resultString, str);
-  AppendString(resultString, DLL_SUFFIX);
+  AppendString(cx, resultString, DLL_PREFIX);
+  AppendString(cx, resultString, str);
+  AppendString(cx, resultString, DLL_SUFFIX);
 
   JSString* result = JS_NewUCStringCopyN(cx, resultString.begin(),
                                          resultString.length());
   if (!result)
     return false;
 
   args.rval().setString(result);
   return true;
@@ -334,31 +334,31 @@ Library::Declare(JSContext* cx, unsigned
   }
 
   void* data;
   PRFuncPtr fnptr;
   RootedString nameStr(cx, args[0].toString());
   AutoCString symbol;
   if (isFunction) {
     // Build the symbol, with mangling if necessary.
-    FunctionType::BuildSymbolName(nameStr, fnObj, symbol);
-    AppendString(symbol, "\0");
+    FunctionType::BuildSymbolName(cx, nameStr, fnObj, symbol);
+    AppendString(cx, symbol, "\0");
 
     // Look up the function symbol.
     fnptr = PR_FindFunctionSymbol(library, symbol.begin());
     if (!fnptr) {
       JS_ReportErrorASCII(cx, "couldn't find function symbol in library");
       return false;
     }
     data = &fnptr;
 
   } else {
     // 'typeObj' is another data type. Look up the data symbol.
-    AppendString(symbol, nameStr);
-    AppendString(symbol, "\0");
+    AppendString(cx, symbol, nameStr);
+    AppendString(cx, symbol, "\0");
 
     data = PR_FindSymbol(library, symbol.begin());
     if (!data) {
       JS_ReportErrorASCII(cx, "couldn't find symbol in library");
       return false;
     }
   }
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1572,16 +1572,18 @@ EqualStringsHelper(JSString* str1, JSStr
 {
     // IC code calls this directly so we shouldn't GC.
     AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(str1->isAtom());
     MOZ_ASSERT(!str2->isAtom());
     MOZ_ASSERT(str1->length() == str2->length());
 
+    // ensureLinear is intentionally called with a nullptr to avoid OOM
+    // reporting; if it fails, we will continue to the next stub.
     JSLinearString* str2Linear = str2->ensureLinear(nullptr);
     if (!str2Linear)
         return false;
 
     return EqualChars(&str1->asLinear(), str2Linear);
 }
 
 bool
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6074,23 +6074,16 @@ JS_PutEscapedString(JSContext* cx, char*
 {
     AssertHeapIsIdle();
     JSLinearString* linearStr = str->ensureLinear(cx);
     if (!linearStr)
         return size_t(-1);
     return PutEscapedString(buffer, size, linearStr, quote);
 }
 
-JS_PUBLIC_API(bool)
-JS_FileEscapedString(FILE* fp, JSString* str, char quote)
-{
-    JSLinearString* linearStr = str->ensureLinear(nullptr);
-    return linearStr && FileEscapedString(fp, linearStr, quote);
-}
-
 JS_PUBLIC_API(JSString*)
 JS_NewDependentString(JSContext* cx, HandleString str, size_t start, size_t length)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     return NewDependentString(cx, str, start, length);
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4712,19 +4712,16 @@ extern JS_PUBLIC_API(bool)
 JS_CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result);
 
 extern JS_PUBLIC_API(bool)
 JS_StringEqualsAscii(JSContext* cx, JSString* str, const char* asciiBytes, bool* match);
 
 extern JS_PUBLIC_API(size_t)
 JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote);
 
-extern JS_PUBLIC_API(bool)
-JS_FileEscapedString(FILE* fp, JSString* str, char quote);
-
 /*
  * Extracting string characters and length.
  *
  * While getting the length of a string is infallible, getting the chars can
  * fail. As indicated by the lack of a JSContext parameter, there are two
  * special cases where getting the chars is infallible:
  *
  * The first case is for strings that have been atomized, e.g. directly by
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -235,16 +235,17 @@ JSLinearString::dumpRepresentationChars(
     out.putChar('\n');
 }
 
 bool
 JSString::equals(const char* s)
 {
     JSLinearString* linear = ensureLinear(nullptr);
     if (!linear) {
+        // This is DEBUG-only code.
         fprintf(stderr, "OOM in JSString::equals!\n");
         return false;
     }
 
     return StringEqualsAscii(linear, s);
 }
 #endif /* DEBUG */