arai-a / smoosh-sync

Automation to make jsparagus and SpiderMonkey bytecode in sync
2 stars 0 forks source link

/js/src/vm/BytecodeUtil.cpp and one more file have been updated (7c627064) #344

Open github-actions[bot] opened 1 year ago

github-actions[bot] commented 1 year ago

Files

Changesets

Diffs

/js/src/vm/BytecodeUtil.cpp

--- d35fc9b3fd75c3cdfc0a3ed6616309c9121f02ec/js/src/vm/BytecodeUtil.cpp
+++ 7c627064647b6afab488b7811c66335dd278b7bc/js/src/vm/BytecodeUtil.cpp
@@ -97,83 +97,65 @@ const char* const js::CodeNameTable[] =

 /************************************************************************/

 static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
                                        UniqueChars* res);

 /* static */ const char PCCounts::numExecName[] = "interp";

-[[nodiscard]] static bool DumpIonScriptCounts(Sprinter* sp, HandleScript script,
+[[nodiscard]] static bool DumpIonScriptCounts(StringPrinter* sp,
+                                              HandleScript script,
                                               jit::IonScriptCounts* ionCounts) {
-  if (!sp->jsprintf("IonScript [%zu blocks]:\n", ionCounts->numBlocks())) {
-    return false;
-  }
+  sp->printf("IonScript [%zu blocks]:\n", ionCounts->numBlocks());

   for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
     const jit::IonBlockCounts& block = ionCounts->block(i);
     unsigned lineNumber = 0;
     JS::LimitedColumnNumberZeroOrigin columnNumber;
     lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()),
                                 &columnNumber);
-    if (!sp->jsprintf("BB #%" PRIu32 " [%05u,%u,%u]", block.id(),
-                      block.offset(), lineNumber,
-                      columnNumber.zeroOriginValue())) {
-      return false;
-    }
+    sp->printf("BB #%" PRIu32 " [%05u,%u,%u]", block.id(), block.offset(),
+               lineNumber, columnNumber.zeroOriginValue());
     if (block.description()) {
-      if (!sp->jsprintf(" [inlined %s]", block.description())) {
-        return false;
-      }
+      sp->printf(" [inlined %s]", block.description());
     }
     for (size_t j = 0; j < block.numSuccessors(); j++) {
-      if (!sp->jsprintf(" -> #%" PRIu32, block.successor(j))) {
-        return false;
-      }
-    }
-    if (!sp->jsprintf(" :: %" PRIu64 " hits\n", block.hitCount())) {
-      return false;
-    }
-    if (!sp->jsprintf("%s\n", block.code())) {
-      return false;
+      sp->printf(" -> #%" PRIu32, block.successor(j));
     }
+    sp->printf(" :: %" PRIu64 " hits\n", block.hitCount());
+    sp->printf("%s\n", block.code());
   }

   return true;
 }

 [[nodiscard]] static bool DumpPCCounts(JSContext* cx, HandleScript script,
-                                       Sprinter* sp) {
+                                       StringPrinter* sp) {
   MOZ_ASSERT(script->hasScriptCounts());

   // Ensure the Disassemble1 call below does not discard the script counts.
   gc::AutoSuppressGC suppress(cx);

 #ifdef DEBUG
   jsbytecode* pc = script->code();
   while (pc < script->codeEnd()) {
     jsbytecode* next = GetNextPc(pc);

     if (!Disassemble1(cx, script, pc, script->pcToOffset(pc), true, sp)) {
       return false;
     }

-    if (!sp->put("                  {")) {
-      return false;
-    }
+    sp->put("                  {");

     PCCounts* counts = script->maybeGetPCCounts(pc);
     if (double val = counts ? counts->numExec() : 0.0) {
-      if (!sp->jsprintf("\"%s\": %.0f", PCCounts::numExecName, val)) {
-        return false;
-      }
-    }
-    if (!sp->put("}\n")) {
-      return false;
+      sp->printf("\"%s\": %.0f", PCCounts::numExecName, val);
     }
+    sp->put("}\n");

     pc = next;
   }
 #endif

   jit::IonScriptCounts* ionCounts = script->getIonCounts();
   while (ionCounts) {
     if (!DumpIonScriptCounts(sp, script, ionCounts)) {
@@ -211,17 +193,21 @@ bool js::DumpRealmPCCounts(JSContext* cx
     const char* filename = script->filename();
     if (!filename) {
       filename = "(unknown)";
     }
     fprintf(stdout, "--- SCRIPT %s:%u ---\n", filename, script->lineno());
     if (!DumpPCCounts(cx, script, &sprinter)) {
       return false;
     }
-    fputs(sprinter.string(), stdout);
+    JS::UniqueChars out = sprinter.release();
+    if (!out) {
+      return false;
+    }
+    fputs(out.get(), stdout);
     fprintf(stdout, "--- END SCRIPT %s:%u ---\n", filename, script->lineno());
   }

   return true;
 }

 /////////////////////////////////////////////////////////////////////
 // Bytecode Parser
@@ -991,157 +977,134 @@ bool js::ReconstructStackDepth(JSContext
     *depth = parser.stackDepthAtPC(pc);
   }

   return true;
 }

 static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
                              unsigned loc, bool lines,
-                             const BytecodeParser* parser, Sprinter* sp);
+                             const BytecodeParser* parser, StringPrinter* sp);

 /*
  * If pc != nullptr, include a prefix indicating whether the PC is at the
  * current line. If showAll is true, include the entry stack depth.
  */
 [[nodiscard]] static bool DisassembleAtPC(
     JSContext* cx, JSScript* scriptArg, bool lines, const jsbytecode* pc,
-    bool showAll, Sprinter* sp,
+    bool showAll, StringPrinter* sp,
     DisassembleSkeptically skeptically = DisassembleSkeptically::No) {
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   RootedScript script(cx, scriptArg);
   mozilla::Maybe<BytecodeParser> parser;

   if (skeptically == DisassembleSkeptically::No) {
     parser.emplace(cx, allocScope.alloc(), script);
     parser->setStackDump();
     if (!parser->parse()) {
       return false;
     }
   }

   if (showAll) {
-    if (!sp->jsprintf("%s:%u\n", script->filename(),
-                      unsigned(script->lineno()))) {
-      return false;
-    }
+    sp->printf("%s:%u\n", script->filename(), unsigned(script->lineno()));
   }

   if (pc != nullptr) {
-    if (!sp->put("    ")) {
-      return false;
-    }
+    sp->put("    ");
   }
   if (showAll) {
-    if (!sp->put("sn stack ")) {
-      return false;
-    }
-  }
-  if (!sp->put("loc   ")) {
-    return false;
+    sp->put("sn stack ");
   }
+  sp->put("loc   ");
   if (lines) {
-    if (!sp->put("line")) {
-      return false;
-    }
-  }
-  if (!sp->put("  op\n")) {
-    return false;
+    sp->put("line");
   }
+  sp->put("  op\n");

   if (pc != nullptr) {
-    if (!sp->put("    ")) {
-      return false;
-    }
+    sp->put("    ");
   }
   if (showAll) {
-    if (!sp->put("-- ----- ")) {
-      return false;
-    }
-  }
-  if (!sp->put("----- ")) {
-    return false;
+    sp->put("-- ----- ");
   }
+  sp->put("----- ");
   if (lines) {
-    if (!sp->put("----")) {
-      return false;
-    }
-  }
-  if (!sp->put("  --\n")) {
-    return false;
+    sp->put("----");
   }
+  sp->put("  --\n");

   jsbytecode* next = script->code();
   jsbytecode* end = script->codeEnd();
   while (next < end) {
     if (next == script->main()) {
-      if (!sp->put("main:\n")) {
-        return false;
-      }
+      sp->put("main:\n");
     }
     if (pc != nullptr) {
-      if (!sp->put(pc == next ? "--> " : "    ")) {
-        return false;
-      }
+      sp->put(pc == next ? "--> " : "    ");
     }
     if (showAll) {
       if (parser && parser->isReachable(next)) {
-        if (!sp->jsprintf("%05u ", parser->stackDepthAtPC(next))) {
-          return false;
-        }
+        sp->printf("%05u ", parser->stackDepthAtPC(next));
       } else {
-        if (!sp->put("      ")) {
-          return false;
-        }
+        sp->put("      ");
       }
     }
     unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next),
                                 lines, parser.ptrOr(nullptr), sp);
     if (!len) {
       return false;
     }

     next += len;
   }

   return true;
 }

 bool js::Disassemble(JSContext* cx, HandleScript script, bool lines,
-                     Sprinter* sp, DisassembleSkeptically skeptically) {
+                     StringPrinter* sp, DisassembleSkeptically skeptically) {
   return DisassembleAtPC(cx, script, lines, nullptr, false, sp, skeptically);
 }

 JS_PUBLIC_API bool js::DumpPC(JSContext* cx, FILE* fp) {
   gc::AutoSuppressGC suppressGC(cx);
   Sprinter sprinter(cx);
   if (!sprinter.init()) {
     return false;
   }
   ScriptFrameIter iter(cx);
   if (iter.done()) {
     fprintf(fp, "Empty stack.\n");
     return true;
   }
   RootedScript script(cx, iter.script());
   bool ok = DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
-  fprintf(fp, "%s", sprinter.string());
+  JS::UniqueChars out = sprinter.release();
+  if (!out) {
+    return false;
+  }
+  fprintf(fp, "%s", out.get());
   return ok;
 }

 JS_PUBLIC_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg,
                                   FILE* fp) {
   gc::AutoSuppressGC suppressGC(cx);
   Sprinter sprinter(cx);
   if (!sprinter.init()) {
     return false;
   }
   RootedScript script(cx, scriptArg);
   bool ok = Disassemble(cx, script, true, &sprinter);
-  fprintf(fp, "%s", sprinter.string());
+  JS::UniqueChars out = sprinter.release();
+  if (!out) {
+    return false;
+  }
+  fprintf(fp, "%s", out.get());
   return ok;
 }

 static UniqueChars ToDisassemblySource(JSContext* cx, HandleValue v) {
   if (v.isString()) {
     return QuoteString(cx, v.toString(), '"');
   }

@@ -1248,165 +1211,136 @@ static bool ToDisassemblySource(JSContex
     return false;
   }

   *bytes = std::move(source);
   return true;
 }

 static bool DumpJumpOrigins(HandleScript script, jsbytecode* pc,
-                            const BytecodeParser* parser, Sprinter* sp) {
+                            const BytecodeParser* parser, StringPrinter* sp) {
   bool called = false;
   auto callback = [&script, &sp, &called](jsbytecode* pc,
                                           BytecodeParser::JumpKind kind) {
     if (!called) {
       called = true;
-      if (!sp->put("\n# ")) {
-        return false;
-      }
+      sp->put("\n# ");
     } else {
-      if (!sp->put(", ")) {
-        return false;
-      }
+      sp->put(", ");
     }

     switch (kind) {
       case BytecodeParser::JumpKind::Simple:
         break;

       case BytecodeParser::JumpKind::SwitchCase:
-        if (!sp->put("switch-case ")) {
-          return false;
-        }
+        sp->put("switch-case ");
         break;

       case BytecodeParser::JumpKind::SwitchDefault:
-        if (!sp->put("switch-default ")) {
-          return false;
-        }
+        sp->put("switch-default ");
         break;

       case BytecodeParser::JumpKind::TryCatch:
-        if (!sp->put("try-catch ")) {
-          return false;
-        }
+        sp->put("try-catch ");
         break;

       case BytecodeParser::JumpKind::TryFinally:
-        if (!sp->put("try-finally ")) {
-          return false;
-        }
+        sp->put("try-finally ");
         break;
     }

-    if (!sp->jsprintf("from %s @ %05u", CodeName(JSOp(*pc)),
-                      unsigned(script->pcToOffset(pc)))) {
-      return false;
-    }
+    sp->printf("from %s @ %05u", CodeName(JSOp(*pc)),
+               unsigned(script->pcToOffset(pc)));

     return true;
   };
   if (!parser->forEachJumpOrigins(pc, callback)) {
     return false;
   }
   if (called) {
-    if (!sp->put("\n")) {
-      return false;
-    }
+    sp->put("\n");
   }

   return true;
 }

 static bool DecompileAtPCForStackDump(
     JSContext* cx, HandleScript script,
-    const OffsetAndDefIndex& offsetAndDefIndex, Sprinter* sp);
+    const OffsetAndDefIndex& offsetAndDefIndex, StringPrinter* sp);

-static bool PrintShapeProperties(JSContext* cx, Sprinter* sp,
+static bool PrintShapeProperties(JSContext* cx, StringPrinter* sp,
                                  SharedShape* shape) {
   // Add all property keys to a vector to allow printing them in property
   // definition order.
   Vector<PropertyKey> props(cx);
   for (SharedShapePropertyIter<NoGC> iter(shape); !iter.done(); iter++) {
     if (!props.append(iter->key())) {
       return false;
     }
   }

-  if (!sp->put("{")) {
-    return false;
-  }
+  sp->put("{");

   for (size_t i = props.length(); i > 0; i--) {
     PropertyKey key = props[i - 1];
     RootedValue keyv(cx, IdToValue(key));
     JSString* str = ToString<NoGC>(cx, keyv);
     if (!str) {
       ReportOutOfMemory(cx);
       return false;
     }
-    if (!sp->putString(str)) {
-      return false;
-    }
+    sp->putString(cx, str);
     if (i > 1) {
-      if (!sp->put(", ")) {
-        return false;
-      }
+      sp->put(", ");
     }
   }

-  return sp->put("}");
+  sp->put("}");
+  return true;
 }

 static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
                              unsigned loc, bool lines,
-                             const BytecodeParser* parser, Sprinter* sp) {
+                             const BytecodeParser* parser, StringPrinter* sp) {
   if (parser && parser->isReachable(pc)) {
     if (!DumpJumpOrigins(script, pc, parser, sp)) {
       return 0;
     }
   }

-  size_t before = sp->stringEnd() - sp->string();
+  size_t before = sp->length();
   bool stackDumped = false;
   auto dumpStack = [&cx, &script, &pc, &parser, &sp, &before, &stackDumped]() {
     if (!parser) {
       return true;
     }
     if (stackDumped) {
       return true;
     }
     stackDumped = true;

-    size_t after = sp->stringEnd() - sp->string();
+    size_t after = sp->length();
     MOZ_ASSERT(after >= before);

     static const size_t stack_column = 40;
     for (size_t i = after - before; i < stack_column - 1; i++) {
-      if (!sp->put(" ")) {
-        return false;
-      }
+      sp->put(" ");
     }

-    if (!sp->put(" # ")) {
-      return false;
-    }
+    sp->put(" # ");

     if (!parser->isReachable(pc)) {
-      if (!sp->put("!!! UNREACHABLE !!!")) {
-        return false;
-      }
+      sp->put("!!! UNREACHABLE !!!");
     } else {
       uint32_t depth = parser->stackDepthAfterPC(pc);

       for (uint32_t i = 0; i < depth; i++) {
         if (i) {
-          if (!sp->put(" ")) {
-            return false;
-          }
+          sp->put(" ");
         }

         const OffsetAndDefIndex& offsetAndDefIndex =
             parser->offsetForStackOperandAfterPC(script->pcToOffset(pc), i);
         // This will decompile the stack for the same PC many times.
         // We'll avoid optimizing it since this is a testing function
         // and it won't be worth managing cached expression here.
         if (!DecompileAtPCForStackDump(cx, script, offsetAndDefIndex, sp)) {
@@ -1424,231 +1358,182 @@ static unsigned Disassemble1(JSContext*
     SprintfLiteral(numBuf2, "%d", JSOP_LIMIT);
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2);
     return 0;
   }
   JSOp op = JSOp(*pc);
   const JSCodeSpec& cs = CodeSpec(op);
   const unsigned len = cs.length;
-  if (!sp->jsprintf("%05u:", loc)) {
-    return 0;
-  }
+  sp->printf("%05u:", loc);
   if (lines) {
-    if (!sp->jsprintf("%4u", PCToLineNumber(script, pc))) {
-      return 0;
-    }
-  }
-  if (!sp->jsprintf("  %s", CodeName(op))) {
-    return 0;
+    sp->printf("%4u", PCToLineNumber(script, pc));
   }
+  sp->printf("  %s", CodeName(op));

   int i;
   switch (JOF_TYPE(cs.format)) {
     case JOF_BYTE:
       break;

     case JOF_JUMP: {
       ptrdiff_t off = GET_JUMP_OFFSET(pc);
-      if (!sp->jsprintf(" %u (%+d)", unsigned(loc + int(off)), int(off))) {
-        return 0;
-      }
+      sp->printf(" %u (%+d)", unsigned(loc + int(off)), int(off));
       break;
     }

     case JOF_SCOPE: {
       Rooted<Scope*> scope(cx, script->getScope(pc));
       UniqueChars bytes;
       if (!ToDisassemblySource(cx, scope, &bytes)) {
         return 0;
       }
-      if (!sp->jsprintf(" %s", bytes.get())) {
-        return 0;
-      }
+      sp->printf(" %s", bytes.get());
       break;
     }

     case JOF_ENVCOORD: {
       RootedValue v(cx, StringValue(EnvironmentCoordinateNameSlow(script, pc)));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
       EnvironmentCoordinate ec(pc);
-      if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(),
-                        ec.slot())) {
-        return 0;
-      }
+      sp->printf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(),
+                 ec.slot());
       break;
     }
     case JOF_DEBUGCOORD: {
       EnvironmentCoordinate ec(pc);
-      if (!sp->jsprintf("(hops = %u, slot = %u)", ec.hops(), ec.slot())) {
-        return 0;
-      }
+      sp->printf("(hops = %u, slot = %u)", ec.hops(), ec.slot());
       break;
     }
     case JOF_ATOM: {
       RootedValue v(cx, StringValue(script->getAtom(pc)));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
-      if (!sp->jsprintf(" %s", bytes.get())) {
-        return 0;
-      }
+      sp->printf(" %s", bytes.get());
       break;
     }
     case JOF_STRING: {
       RootedValue v(cx, StringValue(script->getString(pc)));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
-      if (!sp->jsprintf(" %s", bytes.get())) {
-        return 0;
-      }
+      sp->printf(" %s", bytes.get());
       break;
     }

     case JOF_DOUBLE: {
       double d = GET_INLINE_VALUE(pc).toDouble();
-      if (!sp->jsprintf(" %lf", d)) {
-        return 0;
-      }
+      sp->printf(" %lf", d);
       break;
     }

     case JOF_BIGINT: {
       RootedValue v(cx, BigIntValue(script->getBigInt(pc)));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
-      if (!sp->jsprintf(" %s", bytes.get())) {
-        return 0;
-      }
+      sp->printf(" %s", bytes.get());
       break;
     }

     case JOF_OBJECT: {
       JSObject* obj = script->getObject(pc);
       {
         RootedValue v(cx, ObjectValue(*obj));
         UniqueChars bytes = ToDisassemblySource(cx, v);
         if (!bytes) {
           return 0;
         }
-        if (!sp->jsprintf(" %s", bytes.get())) {
-          return 0;
-        }
+        sp->printf(" %s", bytes.get());
       }
       break;
     }

     case JOF_SHAPE: {
       SharedShape* shape = script->getShape(pc);
-      if (!sp->put(" ")) {
-        return 0;
-      }
+      sp->put(" ");
       if (!PrintShapeProperties(cx, sp, shape)) {
         return 0;
       }
       break;
     }

     case JOF_REGEXP: {
       js::RegExpObject* obj = script->getRegExp(pc);
       RootedValue v(cx, ObjectValue(*obj));
       UniqueChars bytes = ToDisassemblySource(cx, v);
       if (!bytes) {
         return 0;
       }
-      if (!sp->jsprintf(" %s", bytes.get())) {
-        return 0;
-      }
+      sp->printf(" %s", bytes.get());
       break;
     }

     case JOF_TABLESWITCH: {
       int32_t i, low, high;

       ptrdiff_t off = GET_JUMP_OFFSET(pc);
       jsbytecode* pc2 = pc + JUMP_OFFSET_LEN;
       low = GET_JUMP_OFFSET(pc2);
       pc2 += JUMP_OFFSET_LEN;
       high = GET_JUMP_OFFSET(pc2);
       pc2 += JUMP_OFFSET_LEN;
-      if (!sp->jsprintf(" defaultOffset %d low %d high %d", int(off), low,
-                        high)) {
-        return 0;
-      }
+      sp->printf(" defaultOffset %d low %d high %d", int(off), low, high);

       // Display stack dump before diplaying the offsets for each case.
       if (!dumpStack()) {
         return 0;
       }

       for (i = low; i <= high; i++) {
         off =
             script->tableSwitchCaseOffset(pc, i - low) - script->pcToOffset(pc);
-        if (!sp->jsprintf("\n\t%d: %d", i, int(off))) {
-          return 0;
-        }
+        sp->printf("\n\t%d: %d", i, int(off));
       }
       break;
     }

     case JOF_QARG:
-      if (!sp->jsprintf(" %u", GET_ARGNO(pc))) {
-        return 0;
-      }
+      sp->printf(" %u", GET_ARGNO(pc));
       break;

     case JOF_LOCAL:
-      if (!sp->jsprintf(" %u", GET_LOCALNO(pc))) {
-        return 0;
-      }
+      sp->printf(" %u", GET_LOCALNO(pc));
       break;

     case JOF_GCTHING:
-      if (!sp->jsprintf(" %u", unsigned(GET_GCTHING_INDEX(pc)))) {
-        return 0;
-      }
+      sp->printf(" %u", unsigned(GET_GCTHING_INDEX(pc)));
       break;

     case JOF_UINT32:
-      if (!sp->jsprintf(" %u", GET_UINT32(pc))) {
-        return 0;
-      }
+      sp->printf(" %u", GET_UINT32(pc));
       break;

     case JOF_ICINDEX:
-      if (!sp->jsprintf(" (ic: %u)", GET_ICINDEX(pc))) {
-        return 0;
-      }
+      sp->printf(" (ic: %u)", GET_ICINDEX(pc));
       break;

     case JOF_LOOPHEAD:
-      if (!sp->jsprintf(" (ic: %u, depthHint: %u)", GET_ICINDEX(pc),
-                        LoopHeadDepthHint(pc))) {
-        return 0;
-      }
+      sp->printf(" (ic: %u, depthHint: %u)", GET_ICINDEX(pc),
+                 LoopHeadDepthHint(pc));
       break;

     case JOF_TWO_UINT8: {
       int one = (int)GET_UINT8(pc);
       int two = (int)GET_UINT8(pc + 1);

-      if (!sp->jsprintf(" %d", one)) {
-        return 0;
-      }
-      if (!sp->jsprintf(" %d", two)) {
-        return 0;
-      }
+      sp->printf(" %d", one);
+      sp->printf(" %d", two);
       break;
     }

     case JOF_ARGC:
     case JOF_UINT16:
       i = (int)GET_UINT16(pc);
       goto print_int;

@@ -1665,43 +1550,39 @@ static unsigned Disassemble1(JSContext*
     case JOF_INT8:
       i = GET_INT8(pc);
       goto print_int;

     case JOF_INT32:
       MOZ_ASSERT(op == JSOp::Int32);
       i = GET_INT32(pc);
     print_int:
-      if (!sp->jsprintf(" %d", i)) {
-        return 0;
-      }
+      sp->printf(" %d", i);
       break;

     default: {
       char numBuf[12];
       SprintfLiteral(numBuf, "%x", cs.format);
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_UNKNOWN_FORMAT, numBuf);
       return 0;
     }
   }

   if (!dumpStack()) {
     return 0;
   }

-  if (!sp->put("\n")) {
-    return 0;
-  }
+  sp->put("\n");
   return len;
 }

 unsigned js::Disassemble1(JSContext* cx, JS::Handle<JSScript*> script,
                           jsbytecode* pc, unsigned loc, bool lines,
-                          Sprinter* sp) {
+                          StringPrinter* sp) {
   return Disassemble1(cx, script, pc, loc, lines, nullptr, sp);
 }

 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */

 namespace {
 /*
  * The expression decompiler is invoked by error handling code to produce a
@@ -1913,17 +1794,18 @@ bool ExpressionDecompiler::decompilePC(j
     case JSOp::False:
       return write("false");
     case JSOp::Zero:
     case JSOp::One:
     case JSOp::Int8:
     case JSOp::Uint16:
     case JSOp::Uint24:
     case JSOp::Int32:
-      return sprinter.printf("%d", GetBytecodeInteger(pc));
+      sprinter.printf("%d", GetBytecodeInteger(pc));
+      return true;
     case JSOp::String:
       return quote(loadString(pc), '"');
     case JSOp::Symbol: {
       unsigned i = uint8_t(pc[1]);
       MOZ_ASSERT(i < JS::WellKnownSymbolLimit);
       if (i < JS::WellKnownSymbolLimit) {
         return write(cx->names().wellKnownSymbolDescriptions()[i]);
       }
@@ -2069,17 +1951,18 @@ bool ExpressionDecompiler::decompilePC(j
     switch (op) {
       case JSOp::Arguments:
         return write("arguments");

       case JSOp::ArgumentsLength:
         return write("arguments.length");

       case JSOp::GetFrameArg:
-        return sprinter.printf("arguments[%u]", GET_ARGNO(pc));
+        sprinter.printf("arguments[%u]", GET_ARGNO(pc));
+        return true;

       case JSOp::GetActualArg:
         return write("arguments[") && decompilePCForStackOperand(pc, -1) &&
                write("]");

       case JSOp::BindGName:
         return write("GLOBAL");

@@ -2092,17 +1975,18 @@ bool ExpressionDecompiler::decompilePC(j

       case JSOp::EnvCallee:
         return write("ENVCALLEE");

       case JSOp::CallSiteObj:
         return write("OBJ");

       case JSOp::Double:
-        return sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
+        sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
+        return true;

       case JSOp::Exception:
         return write("EXCEPTION");

       case JSOp::Try:
         // Used for the values live on entry to the finally block.
         // See TryNoteKind::Finally above.
         if (defIndex == 0) {
@@ -2278,30 +2162,35 @@ bool ExpressionDecompiler::decompilePC(
                      offsetAndDefIndex.defIndex());
 }

 bool ExpressionDecompiler::init() {
   cx->check(script);
   return sprinter.init();
 }

-bool ExpressionDecompiler::write(const char* s) { return sprinter.put(s); }
+bool ExpressionDecompiler::write(const char* s) {
+  sprinter.put(s);
+  return true;
+}

 bool ExpressionDecompiler::write(JSString* str) {
   if (str == cx->names().dot_this_) {
     return write("this");
   }
   if (str == cx->names().dot_newTarget_) {
     return write("new.target");
   }
-  return sprinter.putString(str);
+  sprinter.putString(cx, str);
+  return true;
 }

 bool ExpressionDecompiler::quote(JSString* s, char quote) {
-  return QuoteString(&sprinter, s, quote);
+  QuoteString(&sprinter, s, quote);
+  return true;
 }

 JSAtom* ExpressionDecompiler::loadAtom(jsbytecode* pc) {
   return script->getAtom(pc);
 }

 JSString* ExpressionDecompiler::loadString(jsbytecode* pc) {
   return script->getString(pc);
@@ -2321,33 +2210,24 @@ JSAtom* ExpressionDecompiler::getArg(uns
       static const char destructuredParam[] = "(destructured parameter)";
       return Atomize(cx, destructuredParam, strlen(destructuredParam));
     }
   }

   MOZ_CRASH("No binding");
 }

-UniqueChars ExpressionDecompiler::getOutput() {
-  ptrdiff_t len = sprinter.stringEnd() - sprinter.stringAt(0);
-  auto res = cx->make_pod_array<char>(len + 1);
-  if (!res) {
-    return nullptr;
-  }
-  js_memcpy(res.get(), sprinter.stringAt(0), len);
-  res[len] = 0;
-  return res;
-}
+UniqueChars ExpressionDecompiler::getOutput() { return sprinter.release(); }

 }  // anonymous namespace

 #if defined(DEBUG) || defined(JS_JITSPEW)
 static bool DecompileAtPCForStackDump(
     JSContext* cx, HandleScript script,
-    const OffsetAndDefIndex& offsetAndDefIndex, Sprinter* sp) {
+    const OffsetAndDefIndex& offsetAndDefIndex, StringPrinter* sp) {
   // The expression decompiler asserts the script is in the current realm.
   AutoRealm ar(cx, script);

   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   BytecodeParser parser(cx, allocScope.alloc(), script);
   parser.setStackDump();
   if (!parser.parse()) {
     return false;
@@ -2363,17 +2243,18 @@ static bool DecompileAtPCForStackDump(
     return false;
   }

   UniqueChars result = ed.getOutput();
   if (!result) {
     return false;
   }

-  return sp->put(result.get());
+  sp->put(result.get());
+  return true;
 }
 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */

 static bool FindStartPC(JSContext* cx, const FrameIter& iter,
                         const BytecodeParser& parser, int spindex,
                         int skipStackHits, const Value& v, jsbytecode** valuepc,
                         uint8_t* defIndex) {
   jsbytecode* current = *valuepc;
@@ -2716,22 +2597,21 @@ size_t JS::GetPCCountScriptCount(JSConte

   if (!rt->scriptAndCountsVector) {
     return 0;
   }

   return rt->scriptAndCountsVector->length();
 }

-[[nodiscard]] static bool JSONStringProperty(Sprinter& sp, JSONPrinter& json,
+[[nodiscard]] static bool JSONStringProperty(StringPrinter& sp,
+                                             JSONPrinter& json,
                                              const char* name, JSString* str) {
   json.beginStringProperty(name);
-  if (!JSONQuoteString(&sp, str)) {
-    return false;
-  }
+  JSONQuoteString(&sp, str);
   json.endStringProperty();
   return true;
 }

 JSString* JS::GetPCCountScriptSummary(JSContext* cx, size_t index) {
   JSRuntime* rt = cx->runtime();

   if (!rt->scriptAndCountsVector ||
@@ -2739,17 +2619,17 @@ JSString* JS::GetPCCountScriptSummary(JS
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BUFFER_TOO_SMALL);
     return nullptr;
   }

   const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
   RootedScript script(cx, sac.script);

-  Sprinter sp(cx);
+  JSSprinter sp(cx);
   if (!sp.init()) {
     return nullptr;
   }

   JSONPrinter json(sp, false);

   json.beginObject();

@@ -2800,25 +2680,21 @@ JSString* JS::GetPCCountScriptSummary(JS
   if (ionActivity) {
     json.property("ion", ionActivity);
   }

   json.endObject();

   json.endObject();

-  if (sp.hadOutOfMemory()) {
-    return nullptr;
-  }
-
-  return NewStringCopyZ<CanGC>(cx, sp.string());
+  return sp.release(cx);
 }

 static bool GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac,
-                           Sprinter& sp) {
+                           StringPrinter& sp) {
   JSONPrinter json(sp, false);

   RootedScript script(cx, sac.script);

   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   BytecodeParser parser(cx, allocScope.alloc(), script);
   if (!parser.parse()) {
     return false;
@@ -2936,49 +2812,50 @@ static bool GetPCCountJSON(JSContext* cx
       ionCounts = ionCounts->previous();
     }

     json.endList();
   }

   json.endObject();

-  return !sp.hadOutOfMemory();
+  if (sp.hadOutOfMemory()) {
+    sp.reportOutOfMemory();
+    return false;
+  }
+
+  return true;
 }

 JSString* JS::GetPCCountScriptContents(JSContext* cx, size_t index) {
   JSRuntime* rt = cx->runtime();

   if (!rt->scriptAndCountsVector ||
       index >= rt->scriptAndCountsVector->length()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BUFFER_TOO_SMALL);
     return nullptr;
   }

   const ScriptAndCounts& sac = (*rt->scriptAndCountsVector)[index];
   JSScript* script = sac.script;

-  Sprinter sp(cx);
+  JSSprinter sp(cx);
   if (!sp.init()) {
     return nullptr;
   }

   {
     AutoRealm ar(cx, &script->global());
     if (!GetPCCountJSON(cx, sac, sp)) {
       return nullptr;
     }
   }

-  if (sp.hadOutOfMemory()) {
-    return nullptr;
-  }
-
-  return NewStringCopyZ<CanGC>(cx, sp.string());
+  return sp.release(cx);
 }

 struct CollectedScripts {
   MutableHandle<ScriptVector> scripts;
   bool ok = true;

   explicit CollectedScripts(MutableHandle<ScriptVector> scripts)
       : scripts(scripts) {}
@@ -3083,46 +2960,42 @@ static bool GenerateLcovInfo(JSContext*
       if (!childScript || !queue.append(childScript)) {
         return false;
       }
     }
   } while (!queue.empty());

   bool isEmpty = true;
   lcovRealm->exportInto(out, &isEmpty);
-  if (out.hadOutOfMemory()) {
-    return false;
-  }
-
   return true;
 }

 JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummaryAll(JSContext* cx,
                                                         size_t* length) {
   Sprinter out(cx);
   if (!out.init()) {
     return nullptr;
   }

   for (RealmsIter realm(cx->runtime()); !realm.done(); realm.next()) {
     if (!GenerateLcovInfo(cx, realm, out)) {
       return nullptr;
     }
   }

-  *length = out.getOffset();
-  return js::DuplicateString(cx, out.string(), *length);
+  *length = out.length();
+  return out.release();
 }

 JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx,
                                                      size_t* length) {
   Sprinter out(cx);
   if (!out.init()) {
     return nullptr;
   }

   if (!GenerateLcovInfo(cx, cx->realm(), out)) {
     return nullptr;
   }

-  *length = out.getOffset();
-  return js::DuplicateString(cx, out.string(), *length);
+  *length = out.length();
+  return out.release();
 }

/js/src/vm/BytecodeUtil.h

--- b713131d3c1f364c35447081832ef027a4d9642e/js/src/vm/BytecodeUtil.h
+++ 16bb2b08c3bfcc489f6aab1cd9bb63fe0c2e0d0a/js/src/vm/BytecodeUtil.h
@@ -27,17 +27,17 @@
 #include "js/Value.h"
 #include "vm/BytecodeFormatFlags.h"  // JOF_*
 #include "vm/GeneratorResumeKind.h"
 #include "vm/Opcodes.h"
 #include "vm/SharedStencil.h"  // js::GCThingIndex
 #include "vm/ThrowMsgKind.h"   // ThrowMsgKind, ThrowCondition

 namespace js {
-class JS_PUBLIC_API Sprinter;
+class JS_PUBLIC_API StringPrinter;
 }  // namespace js

 /* Shorthand for type from format. */

 static inline uint32_t JOF_TYPE(uint32_t fmt) { return fmt & JOF_TYPEMASK; }

 /* Shorthand for mode from format. */

@@ -645,21 +645,22 @@ inline GeneratorResumeKind ResumeKindFro
 #if defined(DEBUG) || defined(JS_JITSPEW)

 enum class DisassembleSkeptically { No, Yes };

 /*
  * Disassemblers, for debugging only.
  */
 [[nodiscard]] extern bool Disassemble(
-    JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp,
+    JSContext* cx, JS::Handle<JSScript*> script, bool lines, StringPrinter* sp,
     DisassembleSkeptically skeptically = DisassembleSkeptically::No);

 unsigned Disassemble1(JSContext* cx, JS::Handle<JSScript*> script,
-                      jsbytecode* pc, unsigned loc, bool lines, Sprinter* sp);
+                      jsbytecode* pc, unsigned loc, bool lines,
+                      StringPrinter* sp);

 #endif

 [[nodiscard]] extern bool DumpRealmPCCounts(JSContext* cx);

 }  // namespace js

 #endif /* vm_BytecodeUtil_h */