summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Printer.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/vm/Printer.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h
new file mode 100644
index 0000000000..d2838766a1
--- /dev/null
+++ b/js/src/vm/Printer.h
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_Printer_h
+#define vm_Printer_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Range.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "js/TypeDecls.h"
+#include "js/Utility.h"
+
+namespace js {
+
+namespace frontend {
+
+class ParserAtom;
+
+} // namespace frontend
+
+class LifoAlloc;
+
+// Generic printf interface, similar to an ostream in the standard library.
+//
+// This class is useful to make generic printers which can work either with a
+// file backend, with a buffer allocated with an JSContext or a link-list
+// of chunks allocated with a LifoAlloc.
+class GenericPrinter {
+ protected:
+ bool hadOOM_; // whether reportOutOfMemory() has been called.
+
+ constexpr GenericPrinter() : hadOOM_(false) {}
+
+ public:
+ // 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();
+
+ // Return true if this Sprinter ran out of memory.
+ virtual bool hadOutOfMemory() const;
+};
+
+// Sprintf, but with unlimited and automatically allocated buffering.
+class Sprinter final : public GenericPrinter {
+ public:
+ struct InvariantChecker {
+ const Sprinter* parent;
+
+ explicit InvariantChecker(const Sprinter* p) : parent(p) {
+ parent->checkInvariants();
+ }
+
+ ~InvariantChecker() { parent->checkInvariants(); }
+ };
+
+ JSContext* context; // context executing the decompiler
+
+ private:
+ static const size_t DefaultSize;
+#ifdef DEBUG
+ bool initialized; // true if this is initialized, use for debug builds
+#endif
+ bool shouldReportOOM; // whether to report OOM to the context
+ char* base; // malloc'd buffer address
+ size_t size; // size of buffer allocated at base
+ ptrdiff_t offset; // offset of next free char in buffer
+
+ MOZ_MUST_USE bool realloc_(size_t newSize);
+
+ public:
+ explicit Sprinter(JSContext* cx, bool shouldReportOOM = true);
+ ~Sprinter();
+
+ // Initialize this sprinter, returns false on error.
+ MOZ_MUST_USE bool init();
+
+ void checkInvariants() const;
+
+ const char* string() const { return base; }
+ const char* stringEnd() const { return base + offset; }
+ JS::UniqueChars release();
+
+ // 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
+ // the internal content. The caller *must* completely fill this space on
+ // success.
+ char* reserve(size_t len);
+
+ // 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) override;
+ using GenericPrinter::put; // pick up |inline bool put(const char* s);|
+
+ // 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).
+ MOZ_MUST_USE bool jsprintf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
+
+ bool putString(JSString* str);
+
+ ptrdiff_t getOffset() const;
+
+ // 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.
+class Fprinter final : public GenericPrinter {
+ private:
+ FILE* file_;
+ bool init_;
+
+ public:
+ explicit Fprinter(FILE* fp);
+
+ constexpr Fprinter() : file_(nullptr), init_(false) {}
+
+#ifdef DEBUG
+ ~Fprinter();
+#endif
+
+ // Initialize this printer, returns false on error.
+ MOZ_MUST_USE bool init(const char* path);
+ void init(FILE* fp);
+ bool isInitialized() const { return file_ != nullptr; }
+ void flush() override;
+ void finish();
+
+ // 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) override;
+ using GenericPrinter::put; // pick up |inline bool put(const char* s);|
+};
+
+// LSprinter, is similar to Sprinter except that instead of using an
+// JSContext to allocate strings, it use a LifoAlloc as a backend for the
+// allocation of the chunk of the string.
+class LSprinter final : public GenericPrinter {
+ private:
+ struct Chunk {
+ Chunk* next;
+ size_t length;
+
+ char* chars() { return reinterpret_cast<char*>(this + 1); }
+ char* end() { return chars() + length; }
+ };
+
+ private:
+ LifoAlloc* alloc_; // LifoAlloc used as a backend of chunk allocations.
+ Chunk* head_;
+ Chunk* tail_;
+ size_t unused_;
+
+ public:
+ explicit LSprinter(LifoAlloc* lifoAlloc);
+ ~LSprinter();
+
+ // Copy the content of the chunks into another printer, such that we can
+ // flush the content of this printer to a file.
+ void exportInto(GenericPrinter& out) const;
+
+ // Drop the current string, and let them be free with the LifoAlloc.
+ void clear();
+
+ // 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) override;
+ using GenericPrinter::put; // pick up |inline bool put(const char* s);|
+};
+
+// Map escaped code to the letter/symbol escaped with a backslash.
+extern const char js_EscapeMap[];
+
+// Return a C-string containing the chars in str, with any non-printing chars
+// escaped. If the optional quote parameter is present and is not '\0', quotes
+// (as specified by the quote argument) are also escaped, and the quote
+// character is appended at the beginning and end of the result string.
+// The returned string is guaranteed to contain only ASCII characters.
+extern JS::UniqueChars QuoteString(JSContext* cx, JSString* str,
+ char quote = '\0');
+
+// Same as above, except quote a parser atom.
+extern JS::UniqueChars QuoteString(JSContext* cx,
+ const frontend::ParserAtom* ent,
+ char quote = '\0');
+
+// Appends the quoted string to the given Sprinter. Follows the same semantics
+// as QuoteString from above.
+extern bool QuoteString(Sprinter* sp, JSString* str, char quote = '\0');
+
+// Appends the quoted parser atom to the given Sprinter. Follows the same
+// semantics as QuoteString from above.
+bool QuoteString(Sprinter* sp, const frontend::ParserAtom* ent,
+ char quote = '\0');
+
+// Appends the JSON quoted string to the given Sprinter.
+extern bool JSONQuoteString(Sprinter* sp, JSString* str);
+
+// Internal implementation code for QuoteString methods above.
+enum class QuoteTarget { String, JSON };
+
+template <QuoteTarget target, typename CharT>
+bool QuoteString(Sprinter* sp, const mozilla::Range<const CharT> chars,
+ char quote = '\0');
+
+} // namespace js
+
+#endif // vm_Printer_h