Open github-actions[bot] opened 1 year ago
/js/src/vm/BytecodeUtil.cpp
/js/src/vm/BytecodeUtil.h
--- 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(); }
--- 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 */
Files
/js/src/vm/BytecodeUtil.cpp
/js/src/vm/BytecodeUtil.h
Changesets
Diffs
/js/src/vm/BytecodeUtil.cpp
/js/src/vm/BytecodeUtil.h