зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 22 changesets (bug 1839396) for causing build bustages on js/Printer.h. CLOSED TREE
Backed out changeset 438a7580a804 (bug 1839396) Backed out changeset 0e43037688b7 (bug 1839396) Backed out changeset 05ffcc50ddb2 (bug 1839396) Backed out changeset 3db0e8cc147f (bug 1839396) Backed out changeset 92310695d5cf (bug 1839396) Backed out changeset 95880ae2420c (bug 1839396) Backed out changeset 8bd5a4df0d37 (bug 1839396) Backed out changeset 9cf77f46cf5e (bug 1839396) Backed out changeset 6ae1dde24527 (bug 1839396) Backed out changeset ffa0fc565bbf (bug 1839396) Backed out changeset ac5d44621417 (bug 1839396) Backed out changeset f1f71378d0a0 (bug 1839396) Backed out changeset ac986f1fee8a (bug 1839396) Backed out changeset f54b604c0c41 (bug 1839396) Backed out changeset 64a0729cfa91 (bug 1839396) Backed out changeset d06c9fc06b6e (bug 1839396) Backed out changeset 861cd467ad0d (bug 1839396) Backed out changeset 5e0270d189f5 (bug 1839396) Backed out changeset 00b288e75acf (bug 1839396) Backed out changeset 21e7991fe154 (bug 1839396) Backed out changeset 0f468ad1a4d1 (bug 1839396) Backed out changeset 91937beca944 (bug 1839396)
This commit is contained in:
Родитель
7c27382e27
Коммит
70df8513eb
|
@ -17078,6 +17078,7 @@ neqo_http3conn_is_zero_rtt
|
|||
?ClassName@js@@YA?AV?$Handle@PAVPropertyName@js@@@JS@@W4JSProtoKey@@PAUJSContext@@@Z
|
||||
?FormatStackDump@JS@@YA?AV?$UniquePtr@$$BY0A@DUFreePolicy@JS@@@mozilla@@PAUJSContext@@_N11@Z
|
||||
?callee@FrameIter@js@@QBEPAVJSFunction@@PAUJSContext@@@Z
|
||||
?jsprintf@Sprinter@js@@QAA_NPBDZZ
|
||||
?vprintf@GenericPrinter@js@@QAE_NPBDPAD@Z
|
||||
?release@Sprinter@js@@QAE?AV?$UniquePtr@$$BY0A@DUFreePolicy@JS@@@mozilla@@XZ
|
||||
??1Sprinter@js@@QAE@XZ
|
||||
|
|
|
@ -16849,6 +16849,7 @@ neqo_http3conn_is_zero_rtt
|
|||
?ClassName@js@@YA?AV?$Handle@PEAVPropertyName@js@@@JS@@W4JSProtoKey@@PEAUJSContext@@@Z
|
||||
?FormatStackDump@JS@@YA?AV?$UniquePtr@$$BY0A@DUFreePolicy@JS@@@mozilla@@PEAUJSContext@@_N11@Z
|
||||
?callee@FrameIter@js@@QEBAPEAVJSFunction@@PEAUJSContext@@@Z
|
||||
?jsprintf@Sprinter@js@@QEAA_NPEBDZZ
|
||||
?vprintf@GenericPrinter@js@@QEAA_NPEBDPEAD@Z
|
||||
?release@Sprinter@js@@QEAA?AV?$UniquePtr@$$BY0A@DUFreePolicy@JS@@@mozilla@@XZ
|
||||
??1Sprinter@js@@QEAA@XZ
|
||||
|
|
|
@ -17,112 +17,6 @@
|
|||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Utility.h"
|
||||
#include "util/Text.h"
|
||||
|
||||
// [SMDOC] *Printer, Sprinter, Fprinter, ...
|
||||
//
|
||||
// # Motivation
|
||||
//
|
||||
// In many places, we want to have functions which are capable of logging
|
||||
// various data structures. Previously, we had logging functions for each
|
||||
// storage, such as using `fwrite`, `printf` or `snprintf`. In additional cases,
|
||||
// many of these logging options were using a string serializing logging
|
||||
// function, only to discard the allocated string after it had been copied to a
|
||||
// file.
|
||||
//
|
||||
// GenericPrinter is an answer to avoid excessive amount of temporary
|
||||
// allocations which are used once, and a way to make logging functions work
|
||||
// independently of the backend they are used with.
|
||||
//
|
||||
// # Design
|
||||
//
|
||||
// The GenericPrinter implements most of `put`, `printf`, `vprintf` and
|
||||
// `putChar` functions, which are implemented using `put` and `putChar`
|
||||
// functions in the derivative classes. Thus, one does not have to reimplement
|
||||
// `putString` nor `printf` for each printer.
|
||||
//
|
||||
// // Logging the value N to whatever printer is provided such as
|
||||
// // a file or a string.
|
||||
// void logN(GenericPrinter& out) {
|
||||
// out.printf("[Logging] %d\n", this->n);
|
||||
// }
|
||||
//
|
||||
// The printing functions are infallible, from the logging functions
|
||||
// perspective. If an issue happens while printing, this would be recorded by
|
||||
// the Printer, and this can be tested using `hadOutOfMemory` function by the
|
||||
// owner of the Printer instance.
|
||||
//
|
||||
// Even in case of failure, printing functions should remain safe to use. Thus
|
||||
// calling `put` twice in a row is safe even if no check for `hadOutOfMemory` is
|
||||
// performed. This is necessary to simplify the control flow and avoid bubble up
|
||||
// failures out of logging functions.
|
||||
//
|
||||
// Note, being safe to use does not imply correctness. In case of failure the
|
||||
// correctness of the printed characters is no longer guarantee. One should use
|
||||
// `hadOutOfMemory` function to know if any failure happened which might have
|
||||
// caused incorrect content to be saved. In some cases, such as `Sprinter`,
|
||||
// where the string buffer can be extracted, the returned value would account
|
||||
// for checking `hadOutOfMemory`.
|
||||
//
|
||||
// # Implementations
|
||||
//
|
||||
// The GenericPrinter is a base class where the derivative classes are providing
|
||||
// different implementations which have their own advantages and disadvantages:
|
||||
//
|
||||
// - Fprinter: FILE* printer. Write the content directly to a file.
|
||||
//
|
||||
// - Sprinter: System allocator C-string buffer. Write the content to a buffer
|
||||
// which is reallocated as more content is added. The buffer can then be
|
||||
// extracted into a C-string or a JSString, respectively using `release` and
|
||||
// `releaseJS`.
|
||||
//
|
||||
// - LSprinter: LifoAlloc C-string rope. Write the content to a list of chunks
|
||||
// in a LifoAlloc buffer, no-reallocation occur but one should use
|
||||
// `exportInto` to serialize its content to a Sprinter or a Fprinter. This is
|
||||
// useful to avoid reallocation copies, while using an existing LifoAlloc.
|
||||
//
|
||||
// - EscapePrinter: Wrapper around other printers, to escape characters when
|
||||
// necessary.
|
||||
//
|
||||
// # Print UTF-16
|
||||
//
|
||||
// The GenericPrinter only handle `char` inputs, which is good enough for ASCII
|
||||
// and Latin1 character sets. However, to handle UTF-16, one should use an
|
||||
// EscapePrinter as well as a policy for escaping characters.
|
||||
//
|
||||
// One might require different escaping policies based on the escape sequences
|
||||
// and based on the set of accepted character for the content generated. For
|
||||
// example, JSON does not specify \x<XX> escape sequences.
|
||||
//
|
||||
// Today the following escape policies exists:
|
||||
//
|
||||
// - StringEscape: Produce C-like escape sequences: \<c>, \x<XX> and \u<XXXX>.
|
||||
// - JSONEscape: Produce JSON escape sequences: \<c> and \u<XXXX>.
|
||||
//
|
||||
// An escape policy is defined by 2 functions:
|
||||
//
|
||||
// bool isSafeChar(char16_t c):
|
||||
// Returns whether a character can be printed without being escaped.
|
||||
//
|
||||
// void convertInto(GenericPrinter& out, char16_t c):
|
||||
// Calls the printer with the escape sequence for the character given as
|
||||
// argument.
|
||||
//
|
||||
// To use an escape policy, the printer should be wrapped using an EscapePrinter
|
||||
// as follows:
|
||||
//
|
||||
// {
|
||||
// // The escaped string is surrounded by double-quotes, escape the double
|
||||
// // quotes as well.
|
||||
// StringEscape esc('"');
|
||||
//
|
||||
// // Wrap our existing `GenericPrinter& out` using the `EscapePrinter`.
|
||||
// EscapePrinter ep(out, esc);
|
||||
//
|
||||
// // Append a sequence of characters which might contain UTF-16 characters.
|
||||
// ep.put(chars);
|
||||
// }
|
||||
//
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -140,67 +34,19 @@ class JS_PUBLIC_API GenericPrinter {
|
|||
constexpr GenericPrinter() : hadOOM_(false) {}
|
||||
|
||||
public:
|
||||
// Puts |len| characters from |s| at the current position. This function might
|
||||
// silently fail and the error can be tested using `hadOutOfMemory()`. Calling
|
||||
// this function or any other printing functions after a failures is accepted,
|
||||
// but the outcome would still remain incorrect and `hadOutOfMemory()` would
|
||||
// still report any of the previous errors.
|
||||
virtual void put(const char* s, size_t len) = 0;
|
||||
inline void put(const char* s) { put(s, strlen(s)); }
|
||||
|
||||
// Put a mozilla::Span / mozilla::Range of Latin1Char or char16_t characters
|
||||
// in the output.
|
||||
//
|
||||
// Note that the char16_t variant is expected to crash unless putChar is
|
||||
// overriden to handle properly the full set of WTF-16 character set.
|
||||
virtual void put(mozilla::Span<const JS::Latin1Char> str);
|
||||
virtual void put(mozilla::Span<const char16_t> str);
|
||||
|
||||
// Same as the various put function but only appending a single character.
|
||||
//
|
||||
// Note that the char16_t variant is expected to crash unless putChar is
|
||||
// overriden to handle properly the full set of WTF-16 character set.
|
||||
virtual inline void putChar(const char c) { put(&c, 1); }
|
||||
virtual inline void putChar(const JS::Latin1Char c) { putChar(char(c)); }
|
||||
virtual inline void putChar(const char16_t c) {
|
||||
MOZ_CRASH("Use an EscapePrinter to handle all characters");
|
||||
}
|
||||
|
||||
virtual void putString(JSContext* cx, JSString* str);
|
||||
|
||||
// Prints a formatted string into the buffer.
|
||||
void printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
|
||||
void vprintf(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
|
||||
|
||||
// In some cases, such as handling JSRopes in a less-quadratic worse-case,
|
||||
// it might be useful to copy content which has already been generated.
|
||||
//
|
||||
// If the buffer is back-readable, then this function should return `true`
|
||||
// and `putFromIndex` should be implemented to delegate to a `put` call at
|
||||
// the matching index and the corresponding length. To provide the index
|
||||
// argument of `putFromIndex`, the `index` method should also be implemented
|
||||
// to return the index within the inner buffer used by the printer.
|
||||
virtual bool canPutFromIndex() const { return false; }
|
||||
|
||||
// Append to the current buffer, bytes which have previously been appended
|
||||
// before.
|
||||
virtual void putFromIndex(size_t index, size_t length) {
|
||||
MOZ_CRASH("Calls to putFromIndex should be guarded by canPutFromIndex.");
|
||||
}
|
||||
|
||||
// When the printer has a seekable buffer and `canPutFromIndex` returns
|
||||
// `true`, this function can return the `index` of the next character to be
|
||||
// added to the buffer.
|
||||
//
|
||||
// This function is monotonic. Thus, if the printer encounter an
|
||||
// Out-Of-Memory issue, then the returned index should be the maximal value
|
||||
// ever returned.
|
||||
virtual size_t index() const { return 0; }
|
||||
|
||||
// In some printers, this ensure that the content is fully written.
|
||||
// Puts |len| characters from |s| at the current position and
|
||||
// return true on success, false on failure.
|
||||
virtual bool put(const char* s, size_t len) = 0;
|
||||
virtual void flush() { /* Do nothing */
|
||||
}
|
||||
|
||||
inline bool put(const char* s) { return put(s, strlen(s)); }
|
||||
inline bool putChar(const char c) { return put(&c, 1); }
|
||||
|
||||
// Prints a formatted string into the buffer.
|
||||
bool printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
|
||||
bool vprintf(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
|
||||
|
||||
// Report that a string operation failed to get the memory it requested.
|
||||
virtual void reportOutOfMemory();
|
||||
|
||||
|
@ -252,8 +98,17 @@ class JS_PUBLIC_API Sprinter final : public GenericPrinter {
|
|||
|
||||
void checkInvariants() const;
|
||||
|
||||
const char* string() const {
|
||||
MOZ_ASSERT(!hadOutOfMemory());
|
||||
return base;
|
||||
}
|
||||
const char* stringEnd() const { return string() + offset; }
|
||||
JS::UniqueChars release();
|
||||
JSString* releaseJS(JSContext* cx);
|
||||
|
||||
// Returns the string at offset |off|.
|
||||
char* stringAt(ptrdiff_t off) const;
|
||||
// Returns the char at offset |off|.
|
||||
char& operator[](size_t off);
|
||||
|
||||
// Attempt to reserve len + 1 space (for a trailing nullptr byte). If the
|
||||
// attempt succeeds, return a pointer to the start of that space and adjust
|
||||
|
@ -263,27 +118,22 @@ class JS_PUBLIC_API Sprinter final : public GenericPrinter {
|
|||
|
||||
// Puts |len| characters from |s| at the current position and
|
||||
// return true on success, false on failure.
|
||||
virtual void put(const char* s, size_t len) override;
|
||||
virtual bool put(const char* s, size_t len) override;
|
||||
using GenericPrinter::put; // pick up |inline bool put(const char* s);|
|
||||
|
||||
virtual bool canPutFromIndex() const override { return true; }
|
||||
virtual void putFromIndex(size_t index, size_t length) override {
|
||||
MOZ_ASSERT(index <= this->index());
|
||||
MOZ_ASSERT(index + length <= this->index());
|
||||
put(base + index, length);
|
||||
}
|
||||
virtual size_t index() const override { return length(); }
|
||||
// Format the given format/arguments as if by JS_vsmprintf, then put it.
|
||||
// Return true on success, else return false and report an error (typically
|
||||
// OOM).
|
||||
[[nodiscard]] bool jsprintf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
|
||||
|
||||
virtual void putString(JSContext* cx, JSString* str) override;
|
||||
bool putString(JSString* str);
|
||||
|
||||
size_t length() const;
|
||||
ptrdiff_t getOffset() const;
|
||||
|
||||
// When an OOM has already been reported on the Sprinter, this function will
|
||||
// forward this error to the JSContext given in the Sprinter initialization.
|
||||
//
|
||||
// If no JSContext had been provided or the Sprinter is configured to not
|
||||
// report OOM, then nothing happens.
|
||||
void forwardOutOfMemory();
|
||||
// Report that a string operation failed to get the memory it requested. The
|
||||
// first call to this function calls JS_ReportOutOfMemory, and sets this
|
||||
// Sprinter's outOfMemory flag; subsequent calls do nothing.
|
||||
virtual void reportOutOfMemory() override;
|
||||
};
|
||||
|
||||
// Fprinter, print a string directly into a file.
|
||||
|
@ -310,7 +160,7 @@ class JS_PUBLIC_API Fprinter final : public GenericPrinter {
|
|||
|
||||
// Puts |len| characters from |s| at the current position and
|
||||
// return true on success, false on failure.
|
||||
virtual void put(const char* s, size_t len) override;
|
||||
virtual bool put(const char* s, size_t len) override;
|
||||
using GenericPrinter::put; // pick up |inline bool put(const char* s);|
|
||||
};
|
||||
|
||||
|
@ -346,106 +196,10 @@ class JS_PUBLIC_API LSprinter final : public GenericPrinter {
|
|||
|
||||
// Puts |len| characters from |s| at the current position and
|
||||
// return true on success, false on failure.
|
||||
virtual void put(const char* s, size_t len) override;
|
||||
virtual bool put(const char* s, size_t len) override;
|
||||
using GenericPrinter::put; // pick up |inline bool put(const char* s);|
|
||||
};
|
||||
|
||||
// Escaping printers work like any other printer except that any added character
|
||||
// are checked for escaping sequences. This one would escape a string such that
|
||||
// it can safely be embedded in a JS string.
|
||||
template <typename Delegate, typename Escape>
|
||||
class JS_PUBLIC_API EscapePrinter final : public GenericPrinter {
|
||||
size_t lengthOfSafeChars(const char* s, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (!esc.isSafeChar(s[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
private:
|
||||
Delegate& out;
|
||||
Escape& esc;
|
||||
|
||||
public:
|
||||
EscapePrinter(Delegate& out, Escape& esc) : out(out), esc(esc) {}
|
||||
~EscapePrinter() {}
|
||||
|
||||
using GenericPrinter::put;
|
||||
void put(const char* s, size_t len) override {
|
||||
const char* b = s;
|
||||
while (len) {
|
||||
size_t index = lengthOfSafeChars(b, len);
|
||||
if (index) {
|
||||
out.put(b, index);
|
||||
len -= index;
|
||||
b += index;
|
||||
}
|
||||
if (len) {
|
||||
esc.convertInto(out, char16_t(*b));
|
||||
len -= 1;
|
||||
b += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void putChar(const char c) override {
|
||||
if (esc.isSafeChar(char16_t(c))) {
|
||||
out.putChar(char(c));
|
||||
return;
|
||||
}
|
||||
esc.convertInto(out, char16_t(c));
|
||||
}
|
||||
|
||||
inline void putChar(const JS::Latin1Char c) override {
|
||||
if (esc.isSafeChar(char16_t(c))) {
|
||||
out.putChar(char(c));
|
||||
return;
|
||||
}
|
||||
esc.convertInto(out, char16_t(c));
|
||||
}
|
||||
|
||||
inline void putChar(const char16_t c) override {
|
||||
if (esc.isSafeChar(c)) {
|
||||
out.putChar(char(c));
|
||||
return;
|
||||
}
|
||||
esc.convertInto(out, c);
|
||||
}
|
||||
|
||||
// Forward calls to delegated printer.
|
||||
bool canPutFromIndex() const override { return out.canPutFromIndex(); }
|
||||
void putFromIndex(size_t index, size_t length) final {
|
||||
out.putFromIndex(index, length);
|
||||
}
|
||||
size_t index() const final { return out.index(); }
|
||||
void flush() final { out.flush(); }
|
||||
void reportOutOfMemory() final { out.reportOutOfMemory(); }
|
||||
bool hadOutOfMemory() const final { return out.hadOutOfMemory(); }
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API JSONEscape {
|
||||
public:
|
||||
inline bool isSafeChar(char16_t c) {
|
||||
return js::IsAsciiPrintable(c) && c != '"' && c != '\\';
|
||||
}
|
||||
void convertInto(GenericPrinter& out, char16_t c);
|
||||
};
|
||||
|
||||
class JS_PUBLIC_API StringEscape {
|
||||
private:
|
||||
const char quote = '\0';
|
||||
|
||||
public:
|
||||
explicit StringEscape(const char quote = '\0') : quote(quote) {}
|
||||
|
||||
inline bool isSafeChar(char16_t c) {
|
||||
return js::IsAsciiPrintable(c) && c != quote && c != '\\';
|
||||
}
|
||||
void convertInto(GenericPrinter& out, char16_t c);
|
||||
};
|
||||
|
||||
// Map escaped code to the letter/symbol escaped with a backslash.
|
||||
extern const char js_EscapeMap[];
|
||||
|
||||
|
@ -459,18 +213,18 @@ extern JS_PUBLIC_API JS::UniqueChars QuoteString(JSContext* cx, JSString* str,
|
|||
|
||||
// Appends the quoted string to the given Sprinter. Follows the same semantics
|
||||
// as QuoteString from above.
|
||||
extern JS_PUBLIC_API void QuoteString(Sprinter* sp, JSString* str,
|
||||
extern JS_PUBLIC_API bool QuoteString(Sprinter* sp, JSString* str,
|
||||
char quote = '\0');
|
||||
|
||||
// Appends the quoted string to the given Sprinter. Follows the same
|
||||
// Appends the JSON quoted string to the given Sprinter.
|
||||
extern JS_PUBLIC_API void JSONQuoteString(Sprinter* sp, JSString* str);
|
||||
extern JS_PUBLIC_API bool JSONQuoteString(Sprinter* sp, JSString* str);
|
||||
|
||||
// Internal implementation code for QuoteString methods above.
|
||||
enum class QuoteTarget { String, JSON };
|
||||
|
||||
template <QuoteTarget target, typename CharT>
|
||||
void JS_PUBLIC_API QuoteString(Sprinter* sp,
|
||||
bool JS_PUBLIC_API QuoteString(Sprinter* sp,
|
||||
const mozilla::Range<const CharT> chars,
|
||||
char quote = '\0');
|
||||
|
||||
|
|
|
@ -1653,11 +1653,12 @@ static bool DisassembleNative(JSContext* cx, unsigned argc, Value* vp) {
|
|||
uint8_t* jit_end = nullptr;
|
||||
|
||||
if (fun->isAsmJSNative() || fun->isWasmWithJitEntry()) {
|
||||
if (fun->isAsmJSNative()) {
|
||||
if (fun->isAsmJSNative() && !sprinter.jsprintf("; backend=asmjs\n")) {
|
||||
return false;
|
||||
}
|
||||
if (!sprinter.jsprintf("; backend=wasm\n")) {
|
||||
return false;
|
||||
}
|
||||
sprinter.printf("; backend=asmjs\n");
|
||||
sprinter.printf("; backend=wasm\n");
|
||||
|
||||
js::wasm::Instance& inst = fun->wasmInstance();
|
||||
const js::wasm::Code& code = inst.code();
|
||||
|
@ -1683,11 +1684,17 @@ static bool DisassembleNative(JSContext* cx, unsigned argc, Value* vp) {
|
|||
js::jit::BaselineScript* baseline =
|
||||
script->hasBaselineScript() ? script->baselineScript() : nullptr;
|
||||
if (ion && ion->method()) {
|
||||
sprinter.printf("; backend=ion\n");
|
||||
if (!sprinter.jsprintf("; backend=ion\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jit_begin = ion->method()->raw();
|
||||
jit_end = ion->method()->rawEnd();
|
||||
} else if (baseline) {
|
||||
sprinter.printf("; backend=baseline\n");
|
||||
if (!sprinter.jsprintf("; backend=baseline\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jit_begin = baseline->method()->raw();
|
||||
jit_end = baseline->method()->rawEnd();
|
||||
}
|
||||
|
@ -1714,7 +1721,7 @@ static bool DisassembleNative(JSContext* cx, unsigned argc, Value* vp) {
|
|||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
sprinter.putString(cx, sresult);
|
||||
sprinter.putString(sresult);
|
||||
|
||||
if (args.length() > 1 && args[1].isString()) {
|
||||
RootedString str(cx, args[1].toString());
|
||||
|
@ -1742,7 +1749,7 @@ static bool DisassembleNative(JSContext* cx, unsigned argc, Value* vp) {
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
JSString* str = sprinter.releaseJS(cx);
|
||||
JSString* str = JS_NewStringCopyZ(cx, sprinter.string());
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6884,7 +6891,11 @@ static bool GetStringRepresentation(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
str->dumpRepresentation(out, 0);
|
||||
|
||||
JSString* rep = out.releaseJS(cx);
|
||||
if (out.hadOutOfMemory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* rep = JS_NewStringCopyN(cx, out.string(), out.getOffset());
|
||||
if (!rep) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1004,7 +1004,9 @@ UniqueChars ToPrintableStringImpl(mozilla::Range<CharT> str,
|
|||
if (!sprinter.init()) {
|
||||
return nullptr;
|
||||
}
|
||||
QuoteString<QuoteTarget::String>(&sprinter, str, quote);
|
||||
if (!QuoteString<QuoteTarget::String>(&sprinter, str, quote)) {
|
||||
return nullptr;
|
||||
}
|
||||
return sprinter.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -909,10 +909,9 @@ void js::Nursery::printCollectionProfile(JS::GCReason reason,
|
|||
stats().maybePrintProfileHeaders();
|
||||
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(gcstats::MinorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(gcstats::MinorGCProfilePrefix);
|
||||
|
||||
size_t pid = getpid();
|
||||
JSRuntime* runtime = gc->rt;
|
||||
|
@ -924,56 +923,55 @@ void js::Nursery::printCollectionProfile(JS::GCReason reason,
|
|||
size_t dedupCount = stats().getStat(gcstats::STAT_STRINGS_DEDUPLICATED);
|
||||
|
||||
#define PRINT_FIELD_VALUE(_1, _2, format, value) \
|
||||
sprinter.printf(" " format, value);
|
||||
|
||||
if (!sprinter.jsprintf(" " format, value)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_NURSERY_PROFILE_METADATA(PRINT_FIELD_VALUE)
|
||||
#undef PRINT_FIELD_VALUE
|
||||
|
||||
printProfileDurations(profileDurations_, sprinter);
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), stats().profileFile());
|
||||
fputs(sprinter.string(), stats().profileFile());
|
||||
}
|
||||
|
||||
void js::Nursery::printProfileHeader() {
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(gcstats::MinorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(gcstats::MinorGCProfilePrefix);
|
||||
|
||||
#define PRINT_FIELD_NAME(name, width, _1, _2) \
|
||||
sprinter.printf(" %-*s", width, name);
|
||||
|
||||
#define PRINT_FIELD_NAME(name, width, _1, _2) \
|
||||
if (!sprinter.jsprintf(" %-*s", width, name)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_NURSERY_PROFILE_METADATA(PRINT_FIELD_NAME)
|
||||
#undef PRINT_FIELD_NAME
|
||||
|
||||
#define PRINT_PROFILE_NAME(_1, text) sprinter.printf(" %-6.6s", text);
|
||||
|
||||
#define PRINT_PROFILE_NAME(_1, text) \
|
||||
if (!sprinter.jsprintf(" %-6.6s", text)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_NURSERY_PROFILE_TIME(PRINT_PROFILE_NAME)
|
||||
#undef PRINT_PROFILE_NAME
|
||||
|
||||
sprinter.put("\n");
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
if (!sprinter.put("\n")) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), stats().profileFile());
|
||||
|
||||
fputs(sprinter.string(), stats().profileFile());
|
||||
}
|
||||
|
||||
// static
|
||||
void js::Nursery::printProfileDurations(const ProfileDurations& times,
|
||||
bool js::Nursery::printProfileDurations(const ProfileDurations& times,
|
||||
Sprinter& sprinter) {
|
||||
for (auto time : times) {
|
||||
int64_t micros = int64_t(time.ToMicroseconds());
|
||||
sprinter.printf(" %6" PRIi64, micros);
|
||||
if (!sprinter.jsprintf(" %6" PRIi64, micros)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sprinter.put("\n");
|
||||
return sprinter.put("\n");
|
||||
}
|
||||
|
||||
static constexpr size_t NurserySliceMetadataFormatWidth() {
|
||||
|
@ -998,10 +996,9 @@ void js::Nursery::printTotalProfileTimes() {
|
|||
}
|
||||
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(gcstats::MinorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(gcstats::MinorGCProfilePrefix);
|
||||
|
||||
size_t pid = getpid();
|
||||
JSRuntime* runtime = gc->rt;
|
||||
|
@ -1012,23 +1009,24 @@ void js::Nursery::printTotalProfileTimes() {
|
|||
MOZ_ASSERT(r > 0 && r < int(sizeof(collections)));
|
||||
|
||||
#define PRINT_FIELD_VALUE(_1, _2, format, value) \
|
||||
sprinter.printf(" " format, value);
|
||||
|
||||
if (!sprinter.jsprintf(" " format, value)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_NURSERY_PROFILE_COMMON_METADATA(PRINT_FIELD_VALUE)
|
||||
#undef PRINT_FIELD_VALUE
|
||||
|
||||
// Use whole width of per-slice metadata to print total slices so the profile
|
||||
// totals that follow line up.
|
||||
size_t width = NurserySliceMetadataFormatWidth();
|
||||
sprinter.printf(" %-*s", int(width), collections);
|
||||
|
||||
printProfileDurations(totalDurations_, sprinter);
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
if (!sprinter.jsprintf(" %-*s", int(width), collections)) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), stats().profileFile());
|
||||
|
||||
if (!printProfileDurations(totalDurations_, sprinter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fputs(sprinter.string(), stats().profileFile());
|
||||
}
|
||||
|
||||
void js::Nursery::maybeClearProfileDurations() {
|
||||
|
|
|
@ -699,7 +699,7 @@ class Nursery {
|
|||
void maybeClearProfileDurations();
|
||||
void startProfile(ProfileKey key);
|
||||
void endProfile(ProfileKey key);
|
||||
static void printProfileDurations(const ProfileDurations& times,
|
||||
static bool printProfileDurations(const ProfileDurations& times,
|
||||
Sprinter& sprinter);
|
||||
|
||||
mozilla::TimeStamp collectionStartTime() const;
|
||||
|
|
|
@ -1640,29 +1640,29 @@ void Statistics::printProfileHeader() {
|
|||
}
|
||||
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(MajorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(MajorGCProfilePrefix);
|
||||
|
||||
#define PRINT_METADATA_NAME(name, width, _1, _2) \
|
||||
sprinter.printf(" %-*s", width, name);
|
||||
|
||||
#define PRINT_METADATA_NAME(name, width, _1, _2) \
|
||||
if (!sprinter.jsprintf(" %-*s", width, name)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_GC_PROFILE_METADATA(PRINT_METADATA_NAME)
|
||||
#undef PRINT_METADATA_NAME
|
||||
|
||||
#define PRINT_PROFILE_NAME(_1, text, _2) sprinter.printf(" %-6.6s", text);
|
||||
|
||||
#define PRINT_PROFILE_NAME(_1, text, _2) \
|
||||
if (!sprinter.jsprintf(" %-6.6s", text)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_GC_PROFILE_TIME(PRINT_PROFILE_NAME)
|
||||
#undef PRINT_PROFILE_NAME
|
||||
|
||||
sprinter.put("\n");
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
if (!sprinter.put("\n")) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), profileFile());
|
||||
|
||||
fputs(sprinter.string(), profileFile());
|
||||
}
|
||||
|
||||
static TimeDuration SumAllPhaseKinds(const Statistics::PhaseKindTimes& times) {
|
||||
|
@ -1681,10 +1681,9 @@ void Statistics::printSliceProfile() {
|
|||
updateTotalProfileTimes(times);
|
||||
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(MajorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(MajorGCProfilePrefix);
|
||||
|
||||
size_t pid = getpid();
|
||||
JSRuntime* runtime = gc->rt;
|
||||
|
@ -1696,18 +1695,17 @@ void Statistics::printSliceProfile() {
|
|||
size_t realmCount = zoneStats.realmCount;
|
||||
|
||||
#define PRINT_FIELD_VALUE(_1, _2, format, value) \
|
||||
sprinter.printf(" " format, value);
|
||||
|
||||
if (!sprinter.jsprintf(" " format, value)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_GC_PROFILE_METADATA(PRINT_FIELD_VALUE)
|
||||
#undef PRINT_FIELD_VALUE
|
||||
|
||||
printProfileTimes(times, sprinter);
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
if (!printProfileTimes(times, sprinter)) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), profileFile());
|
||||
|
||||
fputs(sprinter.string(), profileFile());
|
||||
}
|
||||
|
||||
Statistics::ProfileDurations Statistics::getProfileTimes(
|
||||
|
@ -1772,14 +1770,16 @@ const char* Statistics::formatBudget(const SliceData& slice) {
|
|||
}
|
||||
|
||||
/* static */
|
||||
void Statistics::printProfileTimes(const ProfileDurations& times,
|
||||
bool Statistics::printProfileTimes(const ProfileDurations& times,
|
||||
Sprinter& sprinter) {
|
||||
for (auto time : times) {
|
||||
int64_t millis = int64_t(time.ToMilliseconds());
|
||||
sprinter.printf(" %6" PRIi64, millis);
|
||||
if (!sprinter.jsprintf(" %6" PRIi64, millis)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sprinter.put("\n");
|
||||
return sprinter.put("\n");
|
||||
}
|
||||
|
||||
constexpr size_t SliceMetadataFormatWidth() {
|
||||
|
@ -1804,31 +1804,32 @@ void Statistics::printTotalProfileTimes() {
|
|||
}
|
||||
|
||||
Sprinter sprinter;
|
||||
if (!sprinter.init()) {
|
||||
if (!sprinter.init() || !sprinter.put(MajorGCProfilePrefix)) {
|
||||
return;
|
||||
}
|
||||
sprinter.put(MajorGCProfilePrefix);
|
||||
|
||||
size_t pid = getpid();
|
||||
JSRuntime* runtime = gc->rt;
|
||||
|
||||
#define PRINT_FIELD_VALUE(_1, _2, format, value) \
|
||||
sprinter.printf(" " format, value);
|
||||
|
||||
if (!sprinter.jsprintf(" " format, value)) { \
|
||||
return; \
|
||||
}
|
||||
FOR_EACH_GC_PROFILE_COMMON_METADATA(PRINT_FIELD_VALUE)
|
||||
#undef PRINT_FIELD_VALUE
|
||||
|
||||
// Use whole width of per-slice metadata to print total slices so the profile
|
||||
// totals that follow line up.
|
||||
size_t width = SliceMetadataFormatWidth();
|
||||
sprinter.printf(" %-*s", int(width), formatTotalSlices());
|
||||
printProfileTimes(totalTimes_, sprinter);
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
if (!sprinter.jsprintf(" %-*s", int(width), formatTotalSlices())) {
|
||||
return;
|
||||
}
|
||||
fputs(str.get(), profileFile());
|
||||
|
||||
if (!printProfileTimes(totalTimes_, sprinter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fputs(sprinter.string(), profileFile());
|
||||
}
|
||||
|
||||
const char* Statistics::formatTotalSlices() {
|
||||
|
|
|
@ -497,7 +497,7 @@ struct Statistics {
|
|||
const char* formatGCFlags(const SliceData& slice);
|
||||
const char* formatBudget(const SliceData& slice);
|
||||
const char* formatTotalSlices();
|
||||
static void printProfileTimes(const ProfileDurations& times,
|
||||
static bool printProfileTimes(const ProfileDurations& times,
|
||||
Sprinter& sprinter);
|
||||
};
|
||||
|
||||
|
|
|
@ -7041,8 +7041,8 @@ struct ScriptCountBlockState {
|
|||
~ScriptCountBlockState() {
|
||||
masm.setPrinter(nullptr);
|
||||
|
||||
if (JS::UniqueChars str = printer.release()) {
|
||||
block.setCode(str.get());
|
||||
if (!printer.hadOutOfMemory()) {
|
||||
block.setCode(printer.string());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -457,12 +457,12 @@ UniqueChars LAllocation::toString() const {
|
|||
break;
|
||||
case MIRType::String:
|
||||
// If a JSContext is a available, output the actual string
|
||||
if (JSContext* cx = TlsContext.get()) {
|
||||
Sprinter spr(cx);
|
||||
if (JSContext* maybeCx = TlsContext.get()) {
|
||||
Sprinter spr(maybeCx);
|
||||
if (!spr.init()) {
|
||||
oomUnsafe.crash("LAllocation::toString()");
|
||||
}
|
||||
spr.putString(cx, c->toString());
|
||||
spr.putString(c->toString());
|
||||
buf = spr.release();
|
||||
} else {
|
||||
buf = JS_smprintf("string");
|
||||
|
|
|
@ -495,7 +495,7 @@ void IonPerfSpewer::recordInstruction(MacroAssembler& masm, LInstruction* ins) {
|
|||
if (PerfIROpsEnabled()) {
|
||||
Sprinter buf;
|
||||
CHECK_RETURN(buf.init());
|
||||
buf.put(LIRCodeName(op));
|
||||
CHECK_RETURN(buf.put(LIRCodeName(op)));
|
||||
ins->printOperands(buf);
|
||||
opcodeStr = buf.release();
|
||||
}
|
||||
|
@ -509,53 +509,53 @@ void IonPerfSpewer::recordInstruction(MacroAssembler& masm, LInstruction* ins) {
|
|||
}
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
static void PrintStackValue(JSContext* cx, StackValue* stackVal,
|
||||
CompilerFrameInfo& frame, Sprinter& buf) {
|
||||
static void PrintStackValue(StackValue* stackVal, CompilerFrameInfo& frame,
|
||||
Sprinter& buf) {
|
||||
switch (stackVal->kind()) {
|
||||
/****** Constant ******/
|
||||
case StackValue::Constant: {
|
||||
js::Value constantVal = stackVal->constant();
|
||||
if (constantVal.isInt32()) {
|
||||
buf.printf("%d", constantVal.toInt32());
|
||||
CHECK_RETURN(buf.jsprintf("%d", constantVal.toInt32()));
|
||||
} else if (constantVal.isObjectOrNull()) {
|
||||
buf.printf("obj:%p", constantVal.toObjectOrNull());
|
||||
CHECK_RETURN(buf.jsprintf("obj:%p", constantVal.toObjectOrNull()));
|
||||
} else if (constantVal.isString()) {
|
||||
buf.put("str:");
|
||||
buf.putString(cx, constantVal.toString());
|
||||
CHECK_RETURN(buf.put("str:"));
|
||||
CHECK_RETURN(buf.putString(constantVal.toString()));
|
||||
} else if (constantVal.isNumber()) {
|
||||
buf.printf("num:%f", constantVal.toNumber());
|
||||
CHECK_RETURN(buf.jsprintf("num:%f", constantVal.toNumber()));
|
||||
} else if (constantVal.isSymbol()) {
|
||||
buf.put("sym:");
|
||||
CHECK_RETURN(buf.put("sym:"));
|
||||
constantVal.toSymbol()->dump(buf);
|
||||
} else {
|
||||
buf.printf("raw:%" PRIx64, constantVal.asRawBits());
|
||||
CHECK_RETURN(buf.jsprintf("raw:%" PRIx64, constantVal.asRawBits()));
|
||||
}
|
||||
} break;
|
||||
/****** Register ******/
|
||||
case StackValue::Register: {
|
||||
Register reg = stackVal->reg().payloadOrValueReg();
|
||||
buf.put(reg.name());
|
||||
CHECK_RETURN(buf.put(reg.name()));
|
||||
} break;
|
||||
/****** Stack ******/
|
||||
case StackValue::Stack:
|
||||
buf.put("stack");
|
||||
CHECK_RETURN(buf.put("stack"));
|
||||
break;
|
||||
/****** ThisSlot ******/
|
||||
case StackValue::ThisSlot: {
|
||||
# ifdef JS_HAS_HIDDEN_SP
|
||||
buf.put("this");
|
||||
CHECK_RETURN(buf.put("this"));
|
||||
# else
|
||||
Address addr = frame.addressOfThis();
|
||||
buf.printf("this:%s(%d)", addr.base.name(), addr.offset);
|
||||
CHECK_RETURN(buf.jsprintf("this:%s(%d)", addr.base.name(), addr.offset));
|
||||
# endif
|
||||
} break;
|
||||
/****** LocalSlot ******/
|
||||
case StackValue::LocalSlot:
|
||||
buf.printf("local:%u", stackVal->localSlot());
|
||||
CHECK_RETURN(buf.jsprintf("local:%u", stackVal->localSlot()));
|
||||
break;
|
||||
/****** ArgSlot ******/
|
||||
case StackValue::ArgSlot:
|
||||
buf.printf("arg:%u", stackVal->argSlot());
|
||||
CHECK_RETURN(buf.jsprintf("arg:%u", stackVal->argSlot()));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -582,7 +582,7 @@ void BaselinePerfSpewer::recordInstruction(JSContext* cx, MacroAssembler& masm,
|
|||
|
||||
Sprinter buf(cx);
|
||||
CHECK_RETURN(buf.init());
|
||||
buf.put(js::CodeName(op));
|
||||
CHECK_RETURN(buf.put(js::CodeName(op)));
|
||||
|
||||
switch (op) {
|
||||
case JSOp::SetName:
|
||||
|
@ -593,8 +593,8 @@ void BaselinePerfSpewer::recordInstruction(JSContext* cx, MacroAssembler& masm,
|
|||
case JSOp::GetGName: {
|
||||
// Emit the name used for these ops
|
||||
Rooted<PropertyName*> name(cx, script->getName(pc));
|
||||
buf.put(" ");
|
||||
buf.putString(cx, name);
|
||||
CHECK_RETURN(buf.put(" "));
|
||||
CHECK_RETURN(buf.putString(name));
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
|
@ -602,14 +602,14 @@ void BaselinePerfSpewer::recordInstruction(JSContext* cx, MacroAssembler& masm,
|
|||
|
||||
// Output should be "JSOp (operand1), (operand2), ..."
|
||||
for (unsigned i = 1; i <= numOperands; i++) {
|
||||
buf.put(" (");
|
||||
CHECK_RETURN(buf.put(" ("));
|
||||
StackValue* stackVal = frame.peek(-int(i));
|
||||
PrintStackValue(cx, stackVal, frame, buf);
|
||||
PrintStackValue(stackVal, frame, buf);
|
||||
|
||||
if (i < numOperands) {
|
||||
buf.put("),");
|
||||
CHECK_RETURN(buf.put("),"));
|
||||
} else {
|
||||
buf.put(")");
|
||||
CHECK_RETURN(buf.put(")"));
|
||||
}
|
||||
}
|
||||
opcodeStr = buf.release();
|
||||
|
|
|
@ -1959,12 +1959,8 @@ bool RangeAnalysis::analyzeLoop(MBasicBlock* header) {
|
|||
return false;
|
||||
}
|
||||
iterationBound->boundSum.dump(sp);
|
||||
JS::UniqueChars str = sp.release();
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
JitSpew(JitSpew_Range, "computed symbolic bound on backedges: %s",
|
||||
str.get());
|
||||
sp.string());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3407,7 +3407,7 @@ static bool Notes(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
JSString* str = sprinter.releaseJS(cx);
|
||||
JSString* str = JS_NewStringCopyZ(cx, sprinter.string());
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3489,7 +3489,7 @@ static bool DisassembleToSprinter(JSContext* cx, unsigned argc, Value* vp,
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return !sprinter->hadOutOfMemory();
|
||||
}
|
||||
|
||||
static bool DisassembleToString(JSContext* cx, unsigned argc, Value* vp) {
|
||||
|
@ -3502,7 +3502,16 @@ static bool DisassembleToString(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
JSString* str = sprinter.releaseJS(cx);
|
||||
const char* chars = sprinter.string();
|
||||
size_t len;
|
||||
JS::UniqueTwoByteChars buf(
|
||||
JS::LossyUTF8CharsToNewTwoByteCharsZ(
|
||||
cx, JS::UTF8Chars(chars, strlen(chars)), &len, js::MallocArena)
|
||||
.get());
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
JSString* str = JS_NewUCStringCopyN(cx, buf.get(), len);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3526,11 +3535,7 @@ static bool Disassemble(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
fprintf(gOutFile->fp, "%s\n", str.get());
|
||||
fprintf(gOutFile->fp, "%s\n", sprinter.string());
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
@ -3588,11 +3593,7 @@ static bool DisassFile(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
JS::UniqueChars chars = sprinter.release();
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
fprintf(gOutFile->fp, "%s\n", chars.get());
|
||||
fprintf(gOutFile->fp, "%s\n", sprinter.string());
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
|
@ -3655,11 +3656,15 @@ static bool DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) {
|
|||
if (line2 < line1) {
|
||||
if (bupline != line2) {
|
||||
bupline = line2;
|
||||
sprinter.printf("%s %3u: BACKUP\n", sep, line2);
|
||||
if (!sprinter.jsprintf("%s %3u: BACKUP\n", sep, line2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bupline && line1 == line2) {
|
||||
sprinter.printf("%s %3u: RESTORE\n", sep, line2);
|
||||
if (!sprinter.jsprintf("%s %3u: RESTORE\n", sep, line2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bupline = 0;
|
||||
while (line1 < line2) {
|
||||
|
@ -3669,7 +3674,9 @@ static bool DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
line1++;
|
||||
sprinter.printf("%s %3u: %s", sep, line1, linebuf);
|
||||
if (!sprinter.jsprintf("%s %3u: %s", sep, line1, linebuf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3682,11 +3689,7 @@ static bool DisassWithSrc(JSContext* cx, unsigned argc, Value* vp) {
|
|||
pc += len;
|
||||
}
|
||||
|
||||
JS::UniqueChars str = sprinter.release();
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
fprintf(gOutFile->fp, "%s\n", str.get());
|
||||
fprintf(gOutFile->fp, "%s\n", sprinter.string());
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
|
|
|
@ -285,11 +285,17 @@ static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
if (!funbytes) {
|
||||
return false;
|
||||
}
|
||||
sp.printf("%d %s(", num, funbytes.get());
|
||||
if (!sp.printf("%d %s(", num, funbytes.get())) {
|
||||
return false;
|
||||
}
|
||||
} else if (fun) {
|
||||
sp.printf("%d anonymous(", num);
|
||||
if (!sp.printf("%d anonymous(", num)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp.printf("%d <TOP LEVEL>", num);
|
||||
if (!sp.printf("%d <TOP LEVEL>", num)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (showArgs && iter.hasArgs()) {
|
||||
|
@ -340,23 +346,28 @@ static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
}
|
||||
|
||||
if (value) {
|
||||
sp.printf("%s%s%s%s%s%s", !first ? ", " : "", name ? name : "",
|
||||
name ? " = " : "", arg.isString() ? "\"" : "", value,
|
||||
arg.isString() ? "\"" : "");
|
||||
if (!sp.printf("%s%s%s%s%s%s", !first ? ", " : "", name ? name : "",
|
||||
name ? " = " : "", arg.isString() ? "\"" : "", value,
|
||||
arg.isString() ? "\"" : "")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
first = false;
|
||||
} else {
|
||||
sp.put(
|
||||
" <Failed to get argument while inspecting stack "
|
||||
"frame>\n");
|
||||
if (!sp.put(" <Failed to get argument while inspecting stack "
|
||||
"frame>\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print filename, line number and column
|
||||
sp.printf("%s [\"%s\":%u:%u]\n", fun ? ")" : "",
|
||||
filename ? filename : "<unknown>", lineno,
|
||||
column.zeroOriginValue());
|
||||
if (!sp.printf("%s [\"%s\":%u:%u]\n", fun ? ")" : "",
|
||||
filename ? filename : "<unknown>", lineno,
|
||||
column.zeroOriginValue())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: Right now we don't dump the local variables anymore, because
|
||||
// that is hard to support across all the JITs etc.
|
||||
|
@ -376,9 +387,13 @@ static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
if (!thisValBytes) {
|
||||
return false;
|
||||
}
|
||||
sp.printf(" this = %s\n", thisValBytes.get());
|
||||
if (!sp.printf(" this = %s\n", thisValBytes.get())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp.put(" <failed to get 'this' value>\n");
|
||||
if (!sp.put(" <failed to get 'this' value>\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -404,9 +419,10 @@ static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
return false;
|
||||
}
|
||||
cx->clearPendingException();
|
||||
sp.put(
|
||||
" <Failed to fetch property while inspecting stack "
|
||||
"frame>\n");
|
||||
if (!sp.put(" <Failed to fetch property while inspecting stack "
|
||||
"frame>\n")) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -429,12 +445,15 @@ static bool FormatFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
}
|
||||
|
||||
if (name && value) {
|
||||
sp.printf(" this.%s = %s%s%s\n", name, v.isString() ? "\"" : "",
|
||||
value, v.isString() ? "\"" : "");
|
||||
if (!sp.printf(" this.%s = %s%s%s\n", name, v.isString() ? "\"" : "",
|
||||
value, v.isString() ? "\"" : "")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp.put(
|
||||
" <Failed to format values while inspecting stack "
|
||||
"frame>\n");
|
||||
if (!sp.put(" <Failed to format values while inspecting stack "
|
||||
"frame>\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,10 +472,15 @@ static bool FormatWasmFrame(JSContext* cx, const FrameIter& iter, Sprinter& sp,
|
|||
}
|
||||
}
|
||||
|
||||
sp.printf("%d %s()", num, nameStr ? nameStr.get() : "<wasm-function>");
|
||||
sp.printf(" [\"%s\":wasm-function[%u]:0x%x]\n",
|
||||
iter.filename() ? iter.filename() : "<unknown>",
|
||||
iter.wasmFuncIndex(), iter.wasmBytecodeOffset());
|
||||
if (!sp.printf("%d %s()", num, nameStr ? nameStr.get() : "<wasm-function>")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sp.printf(" [\"%s\":wasm-function[%u]:0x%x]\n",
|
||||
iter.filename() ? iter.filename() : "<unknown>",
|
||||
iter.wasmFuncIndex(), iter.wasmBytecodeOffset())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
return true;
|
||||
|
@ -482,7 +506,9 @@ JS::UniqueChars JS::FormatStackDump(JSContext* cx, bool showArgs,
|
|||
}
|
||||
|
||||
if (num == 0) {
|
||||
sp.put("JavaScript stack is empty\n");
|
||||
if (!sp.put("JavaScript stack is empty\n")) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return sp.release();
|
||||
|
|
|
@ -368,7 +368,9 @@ size_t js::PutEscapedStringImpl(char* buffer, size_t bufferSize,
|
|||
buffer = nullptr;
|
||||
}
|
||||
} else if (out) {
|
||||
out->put(&c, 1);
|
||||
if (!out->put(&c, 1)) {
|
||||
return size_t(-1);
|
||||
}
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
|
|
@ -104,7 +104,9 @@ static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
|
|||
|
||||
[[nodiscard]] static bool DumpIonScriptCounts(Sprinter* sp, HandleScript script,
|
||||
jit::IonScriptCounts* ionCounts) {
|
||||
sp->printf("IonScript [%zu blocks]:\n", ionCounts->numBlocks());
|
||||
if (!sp->jsprintf("IonScript [%zu blocks]:\n", ionCounts->numBlocks())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
|
||||
const jit::IonBlockCounts& block = ionCounts->block(i);
|
||||
|
@ -112,16 +114,27 @@ static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
|
|||
JS::LimitedColumnNumberZeroOrigin columnNumber;
|
||||
lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()),
|
||||
&columnNumber);
|
||||
sp->printf("BB #%" PRIu32 " [%05u,%u,%u]", block.id(), block.offset(),
|
||||
lineNumber, columnNumber.zeroOriginValue());
|
||||
if (!sp->jsprintf("BB #%" PRIu32 " [%05u,%u,%u]", block.id(),
|
||||
block.offset(), lineNumber,
|
||||
columnNumber.zeroOriginValue())) {
|
||||
return false;
|
||||
}
|
||||
if (block.description()) {
|
||||
sp->printf(" [inlined %s]", block.description());
|
||||
if (!sp->jsprintf(" [inlined %s]", block.description())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (size_t j = 0; j < block.numSuccessors(); j++) {
|
||||
sp->printf(" -> #%" PRIu32, block.successor(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(" :: %" PRIu64 " hits\n", block.hitCount());
|
||||
sp->printf("%s\n", block.code());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -143,13 +156,19 @@ static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
|
|||
return false;
|
||||
}
|
||||
|
||||
sp->put(" {");
|
||||
if (!sp->put(" {")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PCCounts* counts = script->maybeGetPCCounts(pc);
|
||||
if (double val = counts ? counts->numExec() : 0.0) {
|
||||
sp->printf("\"%s\": %.0f", PCCounts::numExecName, val);
|
||||
if (!sp->jsprintf("\"%s\": %.0f", PCCounts::numExecName, val)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->put("}\n")) {
|
||||
return false;
|
||||
}
|
||||
sp->put("}\n");
|
||||
|
||||
pc = next;
|
||||
}
|
||||
|
@ -197,11 +216,7 @@ bool js::DumpRealmPCCounts(JSContext* cx) {
|
|||
if (!DumpPCCounts(cx, script, &sprinter)) {
|
||||
return false;
|
||||
}
|
||||
JS::UniqueChars out = sprinter.release();
|
||||
if (!out) {
|
||||
return false;
|
||||
}
|
||||
fputs(out.get(), stdout);
|
||||
fputs(sprinter.string(), stdout);
|
||||
fprintf(stdout, "--- END SCRIPT %s:%u ---\n", filename, script->lineno());
|
||||
}
|
||||
|
||||
|
@ -1004,47 +1019,78 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
}
|
||||
|
||||
if (showAll) {
|
||||
sp->printf("%s:%u\n", script->filename(), unsigned(script->lineno()));
|
||||
if (!sp->jsprintf("%s:%u\n", script->filename(),
|
||||
unsigned(script->lineno()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pc != nullptr) {
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (showAll) {
|
||||
sp->put("sn stack ");
|
||||
if (!sp->put("sn stack ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->put("loc ")) {
|
||||
return false;
|
||||
}
|
||||
sp->put("loc ");
|
||||
if (lines) {
|
||||
sp->put("line");
|
||||
if (!sp->put("line")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->put(" op\n")) {
|
||||
return false;
|
||||
}
|
||||
sp->put(" op\n");
|
||||
|
||||
if (pc != nullptr) {
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (showAll) {
|
||||
sp->put("-- ----- ");
|
||||
if (!sp->put("-- ----- ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->put("----- ")) {
|
||||
return false;
|
||||
}
|
||||
sp->put("----- ");
|
||||
if (lines) {
|
||||
sp->put("----");
|
||||
if (!sp->put("----")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->put(" --\n")) {
|
||||
return false;
|
||||
}
|
||||
sp->put(" --\n");
|
||||
|
||||
jsbytecode* next = script->code();
|
||||
jsbytecode* end = script->codeEnd();
|
||||
while (next < end) {
|
||||
if (next == script->main()) {
|
||||
sp->put("main:\n");
|
||||
if (!sp->put("main:\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (pc != nullptr) {
|
||||
sp->put(pc == next ? "--> " : " ");
|
||||
if (!sp->put(pc == next ? "--> " : " ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (showAll) {
|
||||
if (parser && parser->isReachable(next)) {
|
||||
sp->printf("%05u ", parser->stackDepthAtPC(next));
|
||||
if (!sp->jsprintf("%05u ", parser->stackDepthAtPC(next))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next),
|
||||
|
@ -1077,11 +1123,7 @@ JS_PUBLIC_API bool js::DumpPC(JSContext* cx, FILE* fp) {
|
|||
}
|
||||
RootedScript script(cx, iter.script());
|
||||
bool ok = DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
|
||||
JS::UniqueChars out = sprinter.release();
|
||||
if (!out) {
|
||||
return false;
|
||||
}
|
||||
fprintf(fp, "%s", out.get());
|
||||
fprintf(fp, "%s", sprinter.string());
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -1094,11 +1136,7 @@ JS_PUBLIC_API bool js::DumpScript(JSContext* cx, JSScript* scriptArg,
|
|||
}
|
||||
RootedScript script(cx, scriptArg);
|
||||
bool ok = Disassemble(cx, script, true, &sprinter);
|
||||
JS::UniqueChars out = sprinter.release();
|
||||
if (!out) {
|
||||
return false;
|
||||
}
|
||||
fprintf(fp, "%s", out.get());
|
||||
fprintf(fp, "%s", sprinter.string());
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -1221,9 +1259,13 @@ static bool DumpJumpOrigins(HandleScript script, jsbytecode* pc,
|
|||
BytecodeParser::JumpKind kind) {
|
||||
if (!called) {
|
||||
called = true;
|
||||
sp->put("\n# ");
|
||||
if (!sp->put("\n# ")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put(", ");
|
||||
if (!sp->put(", ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
|
@ -1231,24 +1273,34 @@ static bool DumpJumpOrigins(HandleScript script, jsbytecode* pc,
|
|||
break;
|
||||
|
||||
case BytecodeParser::JumpKind::SwitchCase:
|
||||
sp->put("switch-case ");
|
||||
if (!sp->put("switch-case ")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case BytecodeParser::JumpKind::SwitchDefault:
|
||||
sp->put("switch-default ");
|
||||
if (!sp->put("switch-default ")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case BytecodeParser::JumpKind::TryCatch:
|
||||
sp->put("try-catch ");
|
||||
if (!sp->put("try-catch ")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case BytecodeParser::JumpKind::TryFinally:
|
||||
sp->put("try-finally ");
|
||||
if (!sp->put("try-finally ")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sp->printf("from %s @ %05u", CodeName(JSOp(*pc)),
|
||||
unsigned(script->pcToOffset(pc)));
|
||||
if (!sp->jsprintf("from %s @ %05u", CodeName(JSOp(*pc)),
|
||||
unsigned(script->pcToOffset(pc)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
@ -1256,7 +1308,9 @@ static bool DumpJumpOrigins(HandleScript script, jsbytecode* pc,
|
|||
return false;
|
||||
}
|
||||
if (called) {
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1277,7 +1331,9 @@ static bool PrintShapeProperties(JSContext* cx, Sprinter* sp,
|
|||
}
|
||||
}
|
||||
|
||||
sp->put("{");
|
||||
if (!sp->put("{")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = props.length(); i > 0; i--) {
|
||||
PropertyKey key = props[i - 1];
|
||||
|
@ -1287,14 +1343,17 @@ static bool PrintShapeProperties(JSContext* cx, Sprinter* sp,
|
|||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
sp->putString(cx, str);
|
||||
if (!sp->putString(str)) {
|
||||
return false;
|
||||
}
|
||||
if (i > 1) {
|
||||
sp->put(", ");
|
||||
if (!sp->put(", ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sp->put("}");
|
||||
return true;
|
||||
return sp->put("}");
|
||||
}
|
||||
|
||||
static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
|
@ -1306,7 +1365,7 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
}
|
||||
}
|
||||
|
||||
size_t before = sp->length();
|
||||
size_t before = sp->stringEnd() - sp->string();
|
||||
bool stackDumped = false;
|
||||
auto dumpStack = [&cx, &script, &pc, &parser, &sp, &before, &stackDumped]() {
|
||||
if (!parser) {
|
||||
|
@ -1317,24 +1376,32 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
}
|
||||
stackDumped = true;
|
||||
|
||||
size_t after = sp->length();
|
||||
size_t after = sp->stringEnd() - sp->string();
|
||||
MOZ_ASSERT(after >= before);
|
||||
|
||||
static const size_t stack_column = 40;
|
||||
for (size_t i = after - before; i < stack_column - 1; i++) {
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sp->put(" # ");
|
||||
if (!sp->put(" # ")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parser->isReachable(pc)) {
|
||||
sp->put("!!! UNREACHABLE !!!");
|
||||
if (!sp->put("!!! UNREACHABLE !!!")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
uint32_t depth = parser->stackDepthAfterPC(pc);
|
||||
|
||||
for (uint32_t i = 0; i < depth; i++) {
|
||||
if (i) {
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const OffsetAndDefIndex& offsetAndDefIndex =
|
||||
|
@ -1362,11 +1429,17 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec& cs = CodeSpec(op);
|
||||
const unsigned len = cs.length;
|
||||
sp->printf("%05u:", loc);
|
||||
if (lines) {
|
||||
sp->printf("%4u", PCToLineNumber(script, pc));
|
||||
if (!sp->jsprintf("%05u:", loc)) {
|
||||
return 0;
|
||||
}
|
||||
if (lines) {
|
||||
if (!sp->jsprintf("%4u", PCToLineNumber(script, pc))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!sp->jsprintf(" %s", CodeName(op))) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", CodeName(op));
|
||||
|
||||
int i;
|
||||
switch (JOF_TYPE(cs.format)) {
|
||||
|
@ -1375,7 +1448,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
|
||||
case JOF_JUMP: {
|
||||
ptrdiff_t off = GET_JUMP_OFFSET(pc);
|
||||
sp->printf(" %u (%+d)", unsigned(loc + int(off)), int(off));
|
||||
if (!sp->jsprintf(" %u (%+d)", unsigned(loc + int(off)), int(off))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1385,7 +1460,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!ToDisassemblySource(cx, scope, &bytes)) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1396,13 +1473,17 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
return 0;
|
||||
}
|
||||
EnvironmentCoordinate ec(pc);
|
||||
sp->printf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(),
|
||||
ec.slot());
|
||||
if (!sp->jsprintf(" %s (hops = %u, slot = %u)", bytes.get(), ec.hops(),
|
||||
ec.slot())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JOF_DEBUGCOORD: {
|
||||
EnvironmentCoordinate ec(pc);
|
||||
sp->printf("(hops = %u, slot = %u)", ec.hops(), ec.slot());
|
||||
if (!sp->jsprintf("(hops = %u, slot = %u)", ec.hops(), ec.slot())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JOF_ATOM: {
|
||||
|
@ -1411,7 +1492,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!bytes) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JOF_STRING: {
|
||||
|
@ -1420,13 +1503,17 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!bytes) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOF_DOUBLE: {
|
||||
double d = GET_INLINE_VALUE(pc).toDouble();
|
||||
sp->printf(" %lf", d);
|
||||
if (!sp->jsprintf(" %lf", d)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1436,7 +1523,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!bytes) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1448,14 +1537,18 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!bytes) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOF_SHAPE: {
|
||||
SharedShape* shape = script->getShape(pc);
|
||||
sp->put(" ");
|
||||
if (!sp->put(" ")) {
|
||||
return 0;
|
||||
}
|
||||
if (!PrintShapeProperties(cx, sp, shape)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1469,7 +1562,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
if (!bytes) {
|
||||
return 0;
|
||||
}
|
||||
sp->printf(" %s", bytes.get());
|
||||
if (!sp->jsprintf(" %s", bytes.get())) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1482,7 +1577,10 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
pc2 += JUMP_OFFSET_LEN;
|
||||
high = GET_JUMP_OFFSET(pc2);
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
sp->printf(" defaultOffset %d low %d high %d", int(off), low, high);
|
||||
if (!sp->jsprintf(" defaultOffset %d low %d high %d", int(off), low,
|
||||
high)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Display stack dump before diplaying the offsets for each case.
|
||||
if (!dumpStack()) {
|
||||
|
@ -1492,42 +1590,60 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
for (i = low; i <= high; i++) {
|
||||
off =
|
||||
script->tableSwitchCaseOffset(pc, i - low) - script->pcToOffset(pc);
|
||||
sp->printf("\n\t%d: %d", i, int(off));
|
||||
if (!sp->jsprintf("\n\t%d: %d", i, int(off))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOF_QARG:
|
||||
sp->printf(" %u", GET_ARGNO(pc));
|
||||
if (!sp->jsprintf(" %u", GET_ARGNO(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_LOCAL:
|
||||
sp->printf(" %u", GET_LOCALNO(pc));
|
||||
if (!sp->jsprintf(" %u", GET_LOCALNO(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_GCTHING:
|
||||
sp->printf(" %u", unsigned(GET_GCTHING_INDEX(pc)));
|
||||
if (!sp->jsprintf(" %u", unsigned(GET_GCTHING_INDEX(pc)))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_UINT32:
|
||||
sp->printf(" %u", GET_UINT32(pc));
|
||||
if (!sp->jsprintf(" %u", GET_UINT32(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_ICINDEX:
|
||||
sp->printf(" (ic: %u)", GET_ICINDEX(pc));
|
||||
if (!sp->jsprintf(" (ic: %u)", GET_ICINDEX(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_LOOPHEAD:
|
||||
sp->printf(" (ic: %u, depthHint: %u)", GET_ICINDEX(pc),
|
||||
LoopHeadDepthHint(pc));
|
||||
if (!sp->jsprintf(" (ic: %u, depthHint: %u)", GET_ICINDEX(pc),
|
||||
LoopHeadDepthHint(pc))) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case JOF_TWO_UINT8: {
|
||||
int one = (int)GET_UINT8(pc);
|
||||
int two = (int)GET_UINT8(pc + 1);
|
||||
|
||||
sp->printf(" %d", one);
|
||||
sp->printf(" %d", two);
|
||||
if (!sp->jsprintf(" %d", one)) {
|
||||
return 0;
|
||||
}
|
||||
if (!sp->jsprintf(" %d", two)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1554,7 +1670,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
MOZ_ASSERT(op == JSOp::Int32);
|
||||
i = GET_INT32(pc);
|
||||
print_int:
|
||||
sp->printf(" %d", i);
|
||||
if (!sp->jsprintf(" %d", i)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
|
@ -1570,7 +1688,9 @@ static unsigned Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -1798,8 +1918,7 @@ bool ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex) {
|
|||
case JSOp::Uint16:
|
||||
case JSOp::Uint24:
|
||||
case JSOp::Int32:
|
||||
sprinter.printf("%d", GetBytecodeInteger(pc));
|
||||
return true;
|
||||
return sprinter.printf("%d", GetBytecodeInteger(pc));
|
||||
case JSOp::String:
|
||||
return quote(loadString(pc), '"');
|
||||
case JSOp::Symbol: {
|
||||
|
@ -1955,8 +2074,7 @@ bool ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex) {
|
|||
return write("arguments.length");
|
||||
|
||||
case JSOp::GetFrameArg:
|
||||
sprinter.printf("arguments[%u]", GET_ARGNO(pc));
|
||||
return true;
|
||||
return sprinter.printf("arguments[%u]", GET_ARGNO(pc));
|
||||
|
||||
case JSOp::GetActualArg:
|
||||
return write("arguments[") && decompilePCForStackOperand(pc, -1) &&
|
||||
|
@ -1979,8 +2097,7 @@ bool ExpressionDecompiler::decompilePC(jsbytecode* pc, uint8_t defIndex) {
|
|||
return write("OBJ");
|
||||
|
||||
case JSOp::Double:
|
||||
sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
|
||||
return true;
|
||||
return sprinter.printf("%lf", GET_INLINE_VALUE(pc).toDouble());
|
||||
|
||||
case JSOp::Exception:
|
||||
return write("EXCEPTION");
|
||||
|
@ -2165,10 +2282,7 @@ bool ExpressionDecompiler::init() {
|
|||
return sprinter.init();
|
||||
}
|
||||
|
||||
bool ExpressionDecompiler::write(const char* s) {
|
||||
sprinter.put(s);
|
||||
return true;
|
||||
}
|
||||
bool ExpressionDecompiler::write(const char* s) { return sprinter.put(s); }
|
||||
|
||||
bool ExpressionDecompiler::write(JSString* str) {
|
||||
if (str == cx->names().dot_this_) {
|
||||
|
@ -2177,13 +2291,11 @@ bool ExpressionDecompiler::write(JSString* str) {
|
|||
if (str == cx->names().dot_newTarget_) {
|
||||
return write("new.target");
|
||||
}
|
||||
sprinter.putString(cx, str);
|
||||
return true;
|
||||
return sprinter.putString(str);
|
||||
}
|
||||
|
||||
bool ExpressionDecompiler::quote(JSString* s, char quote) {
|
||||
QuoteString(&sprinter, s, quote);
|
||||
return true;
|
||||
return QuoteString(&sprinter, s, quote);
|
||||
}
|
||||
|
||||
JSAtom* ExpressionDecompiler::loadAtom(jsbytecode* pc) {
|
||||
|
@ -2213,7 +2325,16 @@ JSAtom* ExpressionDecompiler::getArg(unsigned slot) {
|
|||
MOZ_CRASH("No binding");
|
||||
}
|
||||
|
||||
UniqueChars ExpressionDecompiler::getOutput() { return sprinter.release(); }
|
||||
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;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -2246,8 +2367,7 @@ static bool DecompileAtPCForStackDump(
|
|||
return false;
|
||||
}
|
||||
|
||||
sp->put(result.get());
|
||||
return true;
|
||||
return sp->put(result.get());
|
||||
}
|
||||
#endif /* defined(DEBUG) || defined(JS_JITSPEW) */
|
||||
|
||||
|
@ -2603,7 +2723,9 @@ size_t JS::GetPCCountScriptCount(JSContext* cx) {
|
|||
[[nodiscard]] static bool JSONStringProperty(Sprinter& sp, JSONPrinter& json,
|
||||
const char* name, JSString* str) {
|
||||
json.beginStringProperty(name);
|
||||
JSONQuoteString(&sp, str);
|
||||
if (!JSONQuoteString(&sp, str)) {
|
||||
return false;
|
||||
}
|
||||
json.endStringProperty();
|
||||
return true;
|
||||
}
|
||||
|
@ -2682,7 +2804,11 @@ JSString* JS::GetPCCountScriptSummary(JSContext* cx, size_t index) {
|
|||
|
||||
json.endObject();
|
||||
|
||||
return sp.releaseJS(cx);
|
||||
if (sp.hadOutOfMemory()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NewStringCopyZ<CanGC>(cx, sp.string());
|
||||
}
|
||||
|
||||
static bool GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac,
|
||||
|
@ -2842,7 +2968,11 @@ JSString* JS::GetPCCountScriptContents(JSContext* cx, size_t index) {
|
|||
}
|
||||
}
|
||||
|
||||
return sp.releaseJS(cx);
|
||||
if (sp.hadOutOfMemory()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NewStringCopyZ<CanGC>(cx, sp.string());
|
||||
}
|
||||
|
||||
struct CollectedScripts {
|
||||
|
@ -2957,6 +3087,10 @@ static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm,
|
|||
|
||||
bool isEmpty = true;
|
||||
lcovRealm->exportInto(out, &isEmpty);
|
||||
if (out.hadOutOfMemory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2973,8 +3107,8 @@ JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummaryAll(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
*length = out.length();
|
||||
return out.release();
|
||||
*length = out.getOffset();
|
||||
return js::DuplicateString(cx, out.string(), *length);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx,
|
||||
|
@ -2988,6 +3122,6 @@ JS_PUBLIC_API UniqueChars js::GetCodeCoverageSummary(JSContext* cx,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
*length = out.length();
|
||||
return out.release();
|
||||
*length = out.getOffset();
|
||||
return js::DuplicateString(cx, out.string(), *length);
|
||||
}
|
||||
|
|
|
@ -4163,7 +4163,7 @@ static bool AnalyzeEntrainedVariablesInScript(JSContext* cx,
|
|||
buf.printf("Script ");
|
||||
|
||||
if (JSAtom* name = script->function()->displayAtom()) {
|
||||
buf.putString(cx, name);
|
||||
buf.putString(name);
|
||||
buf.printf(" ");
|
||||
}
|
||||
|
||||
|
@ -4171,7 +4171,7 @@ static bool AnalyzeEntrainedVariablesInScript(JSContext* cx,
|
|||
script->lineno());
|
||||
|
||||
if (JSAtom* name = innerScript->function()->displayAtom()) {
|
||||
buf.putString(cx, name);
|
||||
buf.putString(name);
|
||||
buf.printf(" ");
|
||||
}
|
||||
|
||||
|
@ -4180,14 +4180,10 @@ static bool AnalyzeEntrainedVariablesInScript(JSContext* cx,
|
|||
for (PropertyNameSet::Range r = remainingNames.all(); !r.empty();
|
||||
r.popFront()) {
|
||||
buf.printf(" ");
|
||||
buf.putString(cx, r.front());
|
||||
buf.putString(r.front());
|
||||
}
|
||||
|
||||
JS::UniqueChars str = buf.release();
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
printf("%s\n", str.get());
|
||||
printf("%s\n", buf.string());
|
||||
}
|
||||
|
||||
RootedFunction fun(cx);
|
||||
|
|
|
@ -3247,11 +3247,7 @@ void JSScript::dump(JSContext* cx) {
|
|||
return;
|
||||
}
|
||||
|
||||
JS::UniqueChars str = sp.release();
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "%s\n", str.get());
|
||||
fprintf(stderr, "%s\n", sp.string());
|
||||
}
|
||||
|
||||
void JSScript::dumpRecursive(JSContext* cx) {
|
||||
|
@ -3269,11 +3265,7 @@ void JSScript::dumpRecursive(JSContext* cx) {
|
|||
return;
|
||||
}
|
||||
|
||||
JS::UniqueChars str = sp.release();
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "%s\n", str.get());
|
||||
fprintf(stderr, "%s\n", sp.string());
|
||||
}
|
||||
|
||||
static void DumpMutableScriptFlags(js::JSONPrinter& json,
|
||||
|
@ -3399,7 +3391,9 @@ bool JSScript::dump(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
return false;
|
||||
}
|
||||
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Disassemble(cx, script, /* lines = */ true, sp)) {
|
||||
return false;
|
||||
|
@ -3425,7 +3419,9 @@ bool JSScript::dump(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
|
||||
JSObject* obj = &gcThing.as<JSObject>();
|
||||
if (obj->is<JSFunction>()) {
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSFunction*> fun(cx, &obj->as<JSFunction>());
|
||||
if (fun->isInterpreted()) {
|
||||
|
@ -3438,7 +3434,9 @@ bool JSScript::dump(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put("[native code]\n");
|
||||
if (!sp->put("[native code]\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3450,10 +3448,13 @@ bool JSScript::dump(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
/* static */
|
||||
bool JSScript::dumpSrcNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
||||
js::Sprinter* sp) {
|
||||
sp->put("\nSource notes:\n");
|
||||
sp->printf("%4s %4s %6s %5s %6s %-16s %s\n", "ofs", "line", "column", "pc",
|
||||
"delta", "desc", "args");
|
||||
sp->put("---- ---- ------ ----- ------ ---------------- ------\n");
|
||||
if (!sp->put("\nSource notes:\n") ||
|
||||
!sp->jsprintf("%4s %4s %6s %5s %6s %-16s %s\n", "ofs", "line", "column",
|
||||
"pc", "delta", "desc", "args") ||
|
||||
!sp->put("---- ---- ------ ----- ------ ---------------- ------\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned offset = 0;
|
||||
unsigned lineno = script->lineno();
|
||||
JS::LimitedColumnNumberZeroOrigin column = script->column();
|
||||
|
@ -3466,8 +3467,10 @@ bool JSScript::dumpSrcNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
offset += delta;
|
||||
SrcNoteType type = sn->type();
|
||||
const char* name = sn->name();
|
||||
sp->printf("%3u: %4u %6u %5u [%4u] %-16s", unsigned(sn - notes), lineno,
|
||||
column.zeroOriginValue(), offset, delta, name);
|
||||
if (!sp->jsprintf("%3u: %4u %6u %5u [%4u] %-16s", unsigned(sn - notes),
|
||||
lineno, column.zeroOriginValue(), offset, delta, name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SrcNoteType::Breakpoint:
|
||||
|
@ -3477,21 +3480,28 @@ bool JSScript::dumpSrcNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
|
||||
case SrcNoteType::ColSpan: {
|
||||
JS::ColumnNumberOffset colspan = SrcNote::ColSpan::getSpan(sn);
|
||||
sp->printf(" colspan %u", colspan.value());
|
||||
if (!sp->jsprintf(" colspan %u", colspan.value())) {
|
||||
return false;
|
||||
}
|
||||
column += colspan;
|
||||
break;
|
||||
}
|
||||
|
||||
case SrcNoteType::SetLine:
|
||||
lineno = SrcNote::SetLine::getLine(sn, script->lineno());
|
||||
sp->printf(" lineno %u", lineno);
|
||||
if (!sp->jsprintf(" lineno %u", lineno)) {
|
||||
return false;
|
||||
}
|
||||
column = JS::LimitedColumnNumberZeroOrigin::zero();
|
||||
break;
|
||||
|
||||
case SrcNoteType::SetLineColumn:
|
||||
lineno = SrcNote::SetLineColumn::getLine(sn, script->lineno());
|
||||
column = SrcNote::SetLineColumn::getColumn(sn);
|
||||
sp->printf(" lineno %u column %u", lineno, column.zeroOriginValue());
|
||||
if (!sp->jsprintf(" lineno %u column %u", lineno,
|
||||
column.zeroOriginValue())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SrcNoteType::NewLine:
|
||||
|
@ -3501,14 +3511,19 @@ bool JSScript::dumpSrcNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
|
||||
case SrcNoteType::NewLineColumn:
|
||||
column = SrcNote::NewLineColumn::getColumn(sn);
|
||||
sp->printf(" column %u", column.zeroOriginValue());
|
||||
if (!sp->jsprintf(" column %u", column.zeroOriginValue())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++lineno;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unrecognized srcnote");
|
||||
}
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -3538,11 +3553,16 @@ static const char* TryNoteName(TryNoteKind kind) {
|
|||
/* static */
|
||||
bool JSScript::dumpTryNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
||||
js::Sprinter* sp) {
|
||||
sp->put("\nException table:\nkind stack start end\n");
|
||||
if (!sp->put(
|
||||
"\nException table:\nkind stack start end\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const js::TryNote& tn : script->trynotes()) {
|
||||
sp->printf(" %-16s %6u %8u %8u\n", TryNoteName(tn.kind()), tn.stackDepth,
|
||||
tn.start, tn.start + tn.length);
|
||||
if (!sp->jsprintf(" %-16s %6u %8u %8u\n", TryNoteName(tn.kind()),
|
||||
tn.stackDepth, tn.start, tn.start + tn.length)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3550,20 +3570,32 @@ bool JSScript::dumpTryNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
/* static */
|
||||
bool JSScript::dumpScopeNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
||||
js::Sprinter* sp) {
|
||||
sp->put("\nScope notes:\n index parent start end\n");
|
||||
if (!sp->put("\nScope notes:\n index parent start end\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const ScopeNote& note : script->scopeNotes()) {
|
||||
if (note.index == ScopeNote::NoScopeIndex) {
|
||||
sp->printf("%8s ", "(none)");
|
||||
if (!sp->jsprintf("%8s ", "(none)")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->printf("%8u ", note.index.index);
|
||||
if (!sp->jsprintf("%8u ", note.index.index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (note.parent == ScopeNote::NoScopeIndex) {
|
||||
sp->printf("%8s ", "(none)");
|
||||
if (!sp->jsprintf("%8s ", "(none)")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->printf("%8u ", note.parent);
|
||||
if (!sp->jsprintf("%8u ", note.parent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!sp->jsprintf("%8u %8u\n", note.start, note.start + note.length)) {
|
||||
return false;
|
||||
}
|
||||
sp->printf("%8u %8u\n", note.start, note.start + note.length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -3571,27 +3603,41 @@ bool JSScript::dumpScopeNotes(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
/* static */
|
||||
bool JSScript::dumpGCThings(JSContext* cx, JS::Handle<JSScript*> script,
|
||||
js::Sprinter* sp) {
|
||||
sp->put("\nGC things:\n index type value\n");
|
||||
if (!sp->put("\nGC things:\n index type value\n")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (JS::GCCellPtr gcThing : script->gcthings()) {
|
||||
sp->printf("%8zu ", i);
|
||||
if (!sp->jsprintf("%8zu ", i)) {
|
||||
return false;
|
||||
}
|
||||
if (gcThing.is<JS::BigInt>()) {
|
||||
sp->put("BigInt ");
|
||||
if (!sp->put("BigInt ")) {
|
||||
return false;
|
||||
}
|
||||
gcThing.as<JS::BigInt>().dump(*sp);
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
} else if (gcThing.is<Scope>()) {
|
||||
sp->put("Scope ");
|
||||
if (!sp->put("Scope ")) {
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<Scope*> scope(cx, &gcThing.as<Scope>());
|
||||
if (!Scope::dumpForDisassemble(cx, scope, *sp,
|
||||
" ")) {
|
||||
return false;
|
||||
}
|
||||
sp->put("\n");
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
} else if (gcThing.is<JSObject>()) {
|
||||
JSObject* obj = &gcThing.as<JSObject>();
|
||||
if (obj->is<JSFunction>()) {
|
||||
sp->put("Function ");
|
||||
if (!sp->put("Function ")) {
|
||||
return false;
|
||||
}
|
||||
JS::Rooted<JSFunction*> fun(cx, &obj->as<JSFunction>());
|
||||
if (fun->displayAtom()) {
|
||||
JS::Rooted<JSAtom*> name(cx, fun->displayAtom());
|
||||
|
@ -3599,23 +3645,35 @@ bool JSScript::dumpGCThings(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
if (!utf8chars) {
|
||||
return false;
|
||||
}
|
||||
sp->put(utf8chars.get());
|
||||
if (!sp->put(utf8chars.get())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put("(anonymous)");
|
||||
if (!sp->put("(anonymous)")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fun->hasBaseScript()) {
|
||||
BaseScript* script = fun->baseScript();
|
||||
sp->printf(" @ %u:%u\n", script->lineno(),
|
||||
script->column().zeroOriginValue());
|
||||
if (!sp->jsprintf(" @ %u:%u\n", script->lineno(),
|
||||
script->column().zeroOriginValue())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put(" (no script)\n");
|
||||
if (!sp->put(" (no script)\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (obj->is<RegExpObject>()) {
|
||||
sp->put("RegExp ");
|
||||
if (!sp->put("RegExp ")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put("Object ");
|
||||
if (!sp->put("Object ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> objValue(cx, ObjectValue(*obj));
|
||||
|
@ -3627,24 +3685,39 @@ bool JSScript::dumpGCThings(JSContext* cx, JS::Handle<JSScript*> script,
|
|||
if (!utf8chars) {
|
||||
return false;
|
||||
}
|
||||
sp->put(utf8chars.get());
|
||||
sp->put("\n");
|
||||
if (!sp->put(utf8chars.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (gcThing.is<JSString>()) {
|
||||
JS::Rooted<JSString*> str(cx, &gcThing.as<JSString>());
|
||||
if (str->isAtom()) {
|
||||
sp->put("Atom ");
|
||||
if (!sp->put("Atom ")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put("String ");
|
||||
if (!sp->put("String ")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
JS::UniqueChars chars = QuoteString(cx, str, '"');
|
||||
if (!chars) {
|
||||
return false;
|
||||
}
|
||||
sp->put(chars.get());
|
||||
sp->put("\n");
|
||||
if (!sp->put(chars.get())) {
|
||||
return false;
|
||||
}
|
||||
if (!sp->put("\n")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sp->put("Unknown\n");
|
||||
if (!sp->put("Unknown\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ class GenericPrinterPrintfTarget : public mozilla::PrintfTarget {
|
|||
explicit GenericPrinterPrintfTarget(js::GenericPrinter& p) : printer(p) {}
|
||||
|
||||
bool append(const char* sp, size_t len) override {
|
||||
printer.put(sp, len);
|
||||
return true;
|
||||
return printer.put(sp, len);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -48,64 +47,32 @@ void GenericPrinter::reportOutOfMemory() {
|
|||
hadOOM_ = true;
|
||||
}
|
||||
|
||||
void GenericPrinter::put(mozilla::Span<const JS::Latin1Char> str) {
|
||||
if (!str.Length()) {
|
||||
return;
|
||||
}
|
||||
put(reinterpret_cast<const char*>(&str[0]), str.Length());
|
||||
}
|
||||
|
||||
void GenericPrinter::put(mozilla::Span<const char16_t> str) {
|
||||
for (char16_t c : str) {
|
||||
putChar(c);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPrinter::putString(JSContext* cx, JSString* str) {
|
||||
StringSegmentRange iter(cx);
|
||||
if (!iter.init(str)) {
|
||||
reportOutOfMemory();
|
||||
return;
|
||||
}
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
while (!iter.empty()) {
|
||||
JSLinearString* linear = iter.front();
|
||||
if (linear->hasLatin1Chars()) {
|
||||
put(linear->latin1Range(nogc));
|
||||
} else {
|
||||
put(linear->twoByteRange(nogc));
|
||||
}
|
||||
if (!iter.popFront()) {
|
||||
reportOutOfMemory();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GenericPrinter::printf(const char* fmt, ...) {
|
||||
bool GenericPrinter::printf(const char* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vprintf(fmt, va);
|
||||
bool r = vprintf(fmt, va);
|
||||
va_end(va);
|
||||
return r;
|
||||
}
|
||||
|
||||
void GenericPrinter::vprintf(const char* fmt, va_list ap) {
|
||||
bool GenericPrinter::vprintf(const char* fmt, va_list ap) {
|
||||
// Simple shortcut to avoid allocating strings.
|
||||
if (strchr(fmt, '%') == nullptr) {
|
||||
put(fmt);
|
||||
return put(fmt);
|
||||
}
|
||||
|
||||
GenericPrinterPrintfTarget printer(*this);
|
||||
(void)printer.vprint(fmt, ap);
|
||||
if (!printer.vprint(fmt, ap)) {
|
||||
reportOutOfMemory();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t Sprinter::DefaultSize = 64;
|
||||
|
||||
bool Sprinter::realloc_(size_t newSize) {
|
||||
MOZ_ASSERT(newSize > (size_t)offset);
|
||||
if (hadOOM_) {
|
||||
return false;
|
||||
}
|
||||
char* newBuf = (char*)js_realloc(base, newSize);
|
||||
if (!newBuf) {
|
||||
reportOutOfMemory();
|
||||
|
@ -142,7 +109,6 @@ bool Sprinter::init() {
|
|||
base = js_pod_malloc<char>(DefaultSize);
|
||||
if (!base) {
|
||||
reportOutOfMemory();
|
||||
forwardOutOfMemory();
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
|
@ -161,12 +127,11 @@ void Sprinter::checkInvariants() const {
|
|||
}
|
||||
|
||||
UniqueChars Sprinter::release() {
|
||||
checkInvariants();
|
||||
if (hadOOM_) {
|
||||
forwardOutOfMemory();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
checkInvariants();
|
||||
char* str = base;
|
||||
base = nullptr;
|
||||
offset = size = 0;
|
||||
|
@ -176,58 +141,16 @@ UniqueChars Sprinter::release() {
|
|||
return UniqueChars(str);
|
||||
}
|
||||
|
||||
JSString* Sprinter::releaseJS(JSContext* cx) {
|
||||
if (hadOOM_) {
|
||||
MOZ_ASSERT_IF(maybeCx, maybeCx == cx);
|
||||
forwardOutOfMemory();
|
||||
return nullptr;
|
||||
}
|
||||
char* Sprinter::stringAt(ptrdiff_t off) const {
|
||||
MOZ_ASSERT(!hadOutOfMemory());
|
||||
MOZ_ASSERT(off >= 0 && (size_t)off < size);
|
||||
return base + off;
|
||||
}
|
||||
|
||||
checkInvariants();
|
||||
|
||||
// Extract Sprinter data.
|
||||
size_t len = length();
|
||||
UniqueChars str(base);
|
||||
|
||||
// Reset Sprinter.
|
||||
base = nullptr;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
#ifdef DEBUG
|
||||
initialized = false;
|
||||
#endif
|
||||
|
||||
// Convert extracted data to a JSString, reusing the current buffer whenever
|
||||
// possible.
|
||||
JS::UTF8Chars utf8(str.get(), len);
|
||||
JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8);
|
||||
if (encoding == JS::SmallestEncoding::ASCII) {
|
||||
UniqueLatin1Chars latin1(reinterpret_cast<JS::Latin1Char*>(str.release()));
|
||||
return js::NewString<js::CanGC>(cx, std::move(latin1), len);
|
||||
}
|
||||
|
||||
size_t length;
|
||||
if (encoding == JS::SmallestEncoding::Latin1) {
|
||||
UniqueLatin1Chars latin1(
|
||||
UTF8CharsToNewLatin1CharsZ(cx, utf8, &length, js::StringBufferArena)
|
||||
.get());
|
||||
if (!latin1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return js::NewString<js::CanGC>(cx, std::move(latin1), length);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(encoding == JS::SmallestEncoding::UTF16);
|
||||
|
||||
UniqueTwoByteChars utf16(
|
||||
UTF8CharsToNewTwoByteCharsZ(cx, utf8, &length, js::StringBufferArena)
|
||||
.get());
|
||||
if (!utf16) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return js::NewString<js::CanGC>(cx, std::move(utf16), length);
|
||||
char& Sprinter::operator[](size_t off) {
|
||||
MOZ_ASSERT(!hadOutOfMemory());
|
||||
MOZ_ASSERT(off < size);
|
||||
return *(base + off);
|
||||
}
|
||||
|
||||
char* Sprinter::reserve(size_t len) {
|
||||
|
@ -244,7 +167,7 @@ char* Sprinter::reserve(size_t len) {
|
|||
return sb;
|
||||
}
|
||||
|
||||
void Sprinter::put(const char* s, size_t len) {
|
||||
bool Sprinter::put(const char* s, size_t len) {
|
||||
InvariantChecker ic(this);
|
||||
|
||||
const char* oldBase = base;
|
||||
|
@ -252,36 +175,38 @@ void Sprinter::put(const char* s, size_t len) {
|
|||
|
||||
char* bp = reserve(len);
|
||||
if (!bp) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// s is within the buffer already
|
||||
/* s is within the buffer already */
|
||||
if (s >= oldBase && s < oldEnd) {
|
||||
// Update the source pointer in case of a realloc-ation.
|
||||
size_t index = s - oldBase;
|
||||
s = &base[index];
|
||||
/* buffer was realloc'ed */
|
||||
if (base != oldBase) {
|
||||
s = stringAt(s - oldBase); /* this is where it lives now */
|
||||
}
|
||||
memmove(bp, s, len);
|
||||
} else {
|
||||
js_memcpy(bp, s, len);
|
||||
}
|
||||
|
||||
bp[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sprinter::putString(JSContext* cx, JSString* s) {
|
||||
MOZ_ASSERT(cx);
|
||||
bool Sprinter::putString(JSString* s) {
|
||||
MOZ_ASSERT(maybeCx);
|
||||
InvariantChecker ic(this);
|
||||
|
||||
JSLinearString* linear = s->ensureLinear(cx);
|
||||
JSLinearString* linear = s->ensureLinear(maybeCx);
|
||||
if (!linear) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length = JS::GetDeflatedUTF8StringLength(linear);
|
||||
|
||||
char* buffer = reserve(length);
|
||||
if (!buffer) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::DebugOnly<size_t> written =
|
||||
|
@ -289,15 +214,29 @@ void Sprinter::putString(JSContext* cx, JSString* s) {
|
|||
MOZ_ASSERT(written == length);
|
||||
|
||||
buffer[length] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Sprinter::length() const { return size_t(offset); }
|
||||
ptrdiff_t Sprinter::getOffset() const { return offset; }
|
||||
|
||||
void Sprinter::forwardOutOfMemory() {
|
||||
MOZ_ASSERT(hadOOM_);
|
||||
void Sprinter::reportOutOfMemory() {
|
||||
if (hadOOM_) {
|
||||
return;
|
||||
}
|
||||
if (maybeCx && shouldReportOOM) {
|
||||
ReportOutOfMemory(maybeCx);
|
||||
}
|
||||
hadOOM_ = true;
|
||||
}
|
||||
|
||||
bool Sprinter::jsprintf(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
bool r = vprintf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const char js_EscapeMap[] = {
|
||||
|
@ -329,53 +268,118 @@ static const char JSONEscapeMap[] = {
|
|||
};
|
||||
|
||||
template <QuoteTarget target, typename CharT>
|
||||
JS_PUBLIC_API void QuoteString(Sprinter* sp,
|
||||
JS_PUBLIC_API bool QuoteString(Sprinter* sp,
|
||||
const mozilla::Range<const CharT> chars,
|
||||
char quote) {
|
||||
MOZ_ASSERT_IF(target == QuoteTarget::JSON, quote == '\0');
|
||||
|
||||
using CharPtr = mozilla::RangedPtr<const CharT>;
|
||||
|
||||
const char* escapeMap =
|
||||
(target == QuoteTarget::String) ? js_EscapeMap : JSONEscapeMap;
|
||||
|
||||
if (quote) {
|
||||
sp->putChar(quote);
|
||||
if (!sp->putChar(quote)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (target == QuoteTarget::String) {
|
||||
StringEscape esc(quote);
|
||||
EscapePrinter ep(*sp, esc);
|
||||
ep.put(chars);
|
||||
} else {
|
||||
MOZ_ASSERT(target == QuoteTarget::JSON);
|
||||
JSONEscape esc;
|
||||
EscapePrinter ep(*sp, esc);
|
||||
ep.put(chars);
|
||||
|
||||
const CharPtr end = chars.end();
|
||||
|
||||
/* Loop control variables: end points at end of string sentinel. */
|
||||
for (CharPtr t = chars.begin(); t < end; ++t) {
|
||||
/* Move t forward from s past un-quote-worthy characters. */
|
||||
const CharPtr s = t;
|
||||
char16_t c = *t;
|
||||
while (c < 127 && c != '\\') {
|
||||
if (target == QuoteTarget::String) {
|
||||
if (!IsAsciiPrintable(c) || c == quote || c == '\t') {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (c < ' ' || c == '"') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++t;
|
||||
if (t == end) {
|
||||
break;
|
||||
}
|
||||
c = *t;
|
||||
}
|
||||
|
||||
{
|
||||
ptrdiff_t len = t - s;
|
||||
ptrdiff_t base = sp->getOffset();
|
||||
if (!sp->reserve(len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ptrdiff_t i = 0; i < len; ++i) {
|
||||
(*sp)[base + i] = char(s[i]);
|
||||
}
|
||||
(*sp)[base + len] = '\0';
|
||||
}
|
||||
|
||||
if (t == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Use escapeMap, \u, or \x only if necessary. */
|
||||
const char* escape;
|
||||
if (!(c >> 8) && c != 0 &&
|
||||
(escape = strchr(escapeMap, int(c))) != nullptr) {
|
||||
if (!sp->jsprintf("\\%c", escape[1])) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Use \x only if the high byte is 0 and we're in a quoted string,
|
||||
* because ECMA-262 allows only \u, not \x, in Unicode identifiers
|
||||
* (see bug 621814).
|
||||
*/
|
||||
if (!sp->jsprintf((quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sprint the closing quote and return the quoted string. */
|
||||
if (quote) {
|
||||
sp->putChar(quote);
|
||||
if (!sp->putChar(quote)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template JS_PUBLIC_API void QuoteString<QuoteTarget::String, Latin1Char>(
|
||||
template JS_PUBLIC_API bool QuoteString<QuoteTarget::String, Latin1Char>(
|
||||
Sprinter* sp, const mozilla::Range<const Latin1Char> chars, char quote);
|
||||
|
||||
template JS_PUBLIC_API void QuoteString<QuoteTarget::String, char16_t>(
|
||||
template JS_PUBLIC_API bool QuoteString<QuoteTarget::String, char16_t>(
|
||||
Sprinter* sp, const mozilla::Range<const char16_t> chars, char quote);
|
||||
|
||||
template JS_PUBLIC_API void QuoteString<QuoteTarget::JSON, Latin1Char>(
|
||||
template JS_PUBLIC_API bool QuoteString<QuoteTarget::JSON, Latin1Char>(
|
||||
Sprinter* sp, const mozilla::Range<const Latin1Char> chars, char quote);
|
||||
|
||||
template JS_PUBLIC_API void QuoteString<QuoteTarget::JSON, char16_t>(
|
||||
template JS_PUBLIC_API bool QuoteString<QuoteTarget::JSON, char16_t>(
|
||||
Sprinter* sp, const mozilla::Range<const char16_t> chars, char quote);
|
||||
|
||||
JS_PUBLIC_API void QuoteString(Sprinter* sp, JSString* str,
|
||||
JS_PUBLIC_API bool QuoteString(Sprinter* sp, JSString* str,
|
||||
char quote /*= '\0' */) {
|
||||
MOZ_ASSERT(sp->maybeCx);
|
||||
if (quote) {
|
||||
sp->putChar(quote);
|
||||
}
|
||||
StringEscape esc(quote);
|
||||
EscapePrinter ep(*sp, esc);
|
||||
ep.putString(sp->maybeCx, str);
|
||||
if (quote) {
|
||||
sp->putChar(quote);
|
||||
JSLinearString* linear = str->ensureLinear(sp->maybeCx);
|
||||
if (!linear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
return linear->hasLatin1Chars() ? QuoteString<QuoteTarget::String>(
|
||||
sp, linear->latin1Range(nogc), quote)
|
||||
: QuoteString<QuoteTarget::String>(
|
||||
sp, linear->twoByteRange(nogc), quote);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API UniqueChars QuoteString(JSContext* cx, JSString* str,
|
||||
|
@ -384,15 +388,24 @@ JS_PUBLIC_API UniqueChars QuoteString(JSContext* cx, JSString* str,
|
|||
if (!sprinter.init()) {
|
||||
return nullptr;
|
||||
}
|
||||
QuoteString(&sprinter, str, quote);
|
||||
if (!QuoteString(&sprinter, str, quote)) {
|
||||
return nullptr;
|
||||
}
|
||||
return sprinter.release();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JSONQuoteString(Sprinter* sp, JSString* str) {
|
||||
JS_PUBLIC_API bool JSONQuoteString(Sprinter* sp, JSString* str) {
|
||||
MOZ_ASSERT(sp->maybeCx);
|
||||
JSONEscape esc;
|
||||
EscapePrinter ep(*sp, esc);
|
||||
ep.putString(sp->maybeCx, str);
|
||||
JSLinearString* linear = str->ensureLinear(sp->maybeCx);
|
||||
if (!linear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
return linear->hasLatin1Chars() ? QuoteString<QuoteTarget::JSON>(
|
||||
sp, linear->latin1Range(nogc), '\0')
|
||||
: QuoteString<QuoteTarget::JSON>(
|
||||
sp, linear->twoByteRange(nogc), '\0');
|
||||
}
|
||||
|
||||
Fprinter::Fprinter(FILE* fp) : file_(nullptr), init_(false) { init(fp); }
|
||||
|
@ -430,27 +443,24 @@ void Fprinter::finish() {
|
|||
file_ = nullptr;
|
||||
}
|
||||
|
||||
void Fprinter::put(const char* s, size_t len) {
|
||||
if (hadOutOfMemory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool Fprinter::put(const char* s, size_t len) {
|
||||
MOZ_ASSERT(file_);
|
||||
int i = fwrite(s, /*size=*/1, /*nitems=*/len, file_);
|
||||
if (size_t(i) != len) {
|
||||
reportOutOfMemory();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
if ((file_ == stderr) && (IsDebuggerPresent())) {
|
||||
UniqueChars buf = DuplicateString(s, len);
|
||||
if (!buf) {
|
||||
reportOutOfMemory();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
OutputDebugStringA(buf.get());
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
LSprinter::LSprinter(LifoAlloc* lifoAlloc)
|
||||
|
@ -479,11 +489,7 @@ void LSprinter::clear() {
|
|||
hadOOM_ = false;
|
||||
}
|
||||
|
||||
void LSprinter::put(const char* s, size_t len) {
|
||||
if (hadOutOfMemory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool LSprinter::put(const char* s, size_t len) {
|
||||
// Compute how much data will fit in the current chunk.
|
||||
size_t existingSpaceWrite = 0;
|
||||
size_t overflow = len;
|
||||
|
@ -503,7 +509,7 @@ void LSprinter::put(const char* s, size_t len) {
|
|||
last = reinterpret_cast<Chunk*>(alloc_->alloc(allocLength));
|
||||
if (!last) {
|
||||
reportOutOfMemory();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,28 +553,7 @@ void LSprinter::put(const char* s, size_t len) {
|
|||
}
|
||||
|
||||
MOZ_ASSERT(len <= INT_MAX);
|
||||
}
|
||||
|
||||
void JSONEscape::convertInto(GenericPrinter& out, char16_t c) {
|
||||
const char* escape = nullptr;
|
||||
if (!(c >> 8) && c != 0 &&
|
||||
(escape = strchr(JSONEscapeMap, int(c))) != nullptr) {
|
||||
out.printf("\\%c", escape[1]);
|
||||
} else {
|
||||
out.printf("\\u%04X", c);
|
||||
}
|
||||
}
|
||||
|
||||
void StringEscape::convertInto(GenericPrinter& out, char16_t c) {
|
||||
const char* escape = nullptr;
|
||||
if (!(c >> 8) && c != 0 &&
|
||||
(escape = strchr(js_EscapeMap, int(c))) != nullptr) {
|
||||
out.printf("\\%c", escape[1]);
|
||||
} else {
|
||||
// Use \x only if the high byte is 0 and we're in a quoted string, because
|
||||
// ECMA-262 allows only \u, not \x, in Unicode identifiers (see bug 621814).
|
||||
out.printf(!(c >> 8) ? "\\x%02X" : "\\u%04X", c);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -392,55 +392,88 @@ void Scope::dump() {
|
|||
/* static */
|
||||
bool Scope::dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
|
||||
GenericPrinter& out, const char* indent) {
|
||||
out.put(ScopeKindString(scope->kind()));
|
||||
out.put(" {");
|
||||
if (!out.put(ScopeKindString(scope->kind()))) {
|
||||
return false;
|
||||
}
|
||||
if (!out.put(" {")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++, i++) {
|
||||
if (i == 0) {
|
||||
out.put("\n");
|
||||
if (!out.put("\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UniqueChars bytes = AtomToPrintableString(cx, bi.name());
|
||||
if (!bytes) {
|
||||
return false;
|
||||
}
|
||||
out.put(indent);
|
||||
out.printf(" %2zu: %s %s ", i, BindingKindString(bi.kind()), bytes.get());
|
||||
if (!out.put(indent)) {
|
||||
return false;
|
||||
}
|
||||
if (!out.printf(" %2zu: %s %s ", i, BindingKindString(bi.kind()),
|
||||
bytes.get())) {
|
||||
return false;
|
||||
}
|
||||
switch (bi.location().kind()) {
|
||||
case BindingLocation::Kind::Global:
|
||||
if (bi.isTopLevelFunction()) {
|
||||
out.put("(global function)\n");
|
||||
if (!out.put("(global function)\n")) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
out.put("(global)\n");
|
||||
if (!out.put("(global)\n")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BindingLocation::Kind::Argument:
|
||||
out.printf("(arg slot %u)\n", bi.location().argumentSlot());
|
||||
if (!out.printf("(arg slot %u)\n", bi.location().argumentSlot())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BindingLocation::Kind::Frame:
|
||||
out.printf("(frame slot %u)\n", bi.location().slot());
|
||||
if (!out.printf("(frame slot %u)\n", bi.location().slot())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BindingLocation::Kind::Environment:
|
||||
out.printf("(env slot %u)\n", bi.location().slot());
|
||||
if (!out.printf("(env slot %u)\n", bi.location().slot())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BindingLocation::Kind::NamedLambdaCallee:
|
||||
out.put("(named lambda callee)\n");
|
||||
if (!out.put("(named lambda callee)\n")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BindingLocation::Kind::Import:
|
||||
out.put("(import)\n");
|
||||
if (!out.put("(import)\n")) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i > 0) {
|
||||
out.put(indent);
|
||||
if (!out.put(indent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!out.put("}")) {
|
||||
return false;
|
||||
}
|
||||
out.put("}");
|
||||
|
||||
ScopeIter si(scope);
|
||||
si++;
|
||||
for (; si; si++) {
|
||||
out.put(" -> ");
|
||||
out.put(ScopeKindString(si.kind()));
|
||||
if (!out.put(" -> ")) {
|
||||
return false;
|
||||
}
|
||||
if (!out.put(ScopeKindString(si.kind()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче