Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef vm_Printer_h
8 : #define vm_Printer_h
9 :
10 : #include "mozilla/Attributes.h"
11 :
12 : #include <stdarg.h>
13 : #include <stddef.h>
14 : #include <stdio.h>
15 : #include <string.h>
16 :
17 : class JSString;
18 :
19 : struct JSContext;
20 :
21 : namespace js {
22 :
23 : class LifoAlloc;
24 :
25 : // Generic printf interface, similar to an ostream in the standard library.
26 : //
27 : // This class is useful to make generic printers which can work either with a
28 : // file backend, with a buffer allocated with an JSContext or a link-list
29 : // of chunks allocated with a LifoAlloc.
30 0 : class GenericPrinter
31 : {
32 : protected:
33 : bool hadOOM_; // whether reportOutOfMemory() has been called.
34 :
35 : GenericPrinter();
36 :
37 : public:
38 : // Puts |len| characters from |s| at the current position and
39 : // return true on success, false on failure.
40 : virtual bool put(const char* s, size_t len) = 0;
41 :
42 2 : inline bool put(const char* s) {
43 2 : return put(s, strlen(s));
44 : }
45 :
46 : // Prints a formatted string into the buffer.
47 : bool printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
48 : bool vprintf(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
49 :
50 : // Report that a string operation failed to get the memory it requested.
51 : virtual void reportOutOfMemory();
52 :
53 : // Return true if this Sprinter ran out of memory.
54 : virtual bool hadOutOfMemory() const;
55 : };
56 :
57 : // Sprintf, but with unlimited and automatically allocated buffering.
58 : class Sprinter final : public GenericPrinter
59 : {
60 : public:
61 : struct InvariantChecker
62 : {
63 : const Sprinter* parent;
64 :
65 28 : explicit InvariantChecker(const Sprinter* p) : parent(p) {
66 28 : parent->checkInvariants();
67 28 : }
68 :
69 56 : ~InvariantChecker() {
70 28 : parent->checkInvariants();
71 28 : }
72 : };
73 :
74 : JSContext* context; // context executing the decompiler
75 :
76 : private:
77 : static const size_t DefaultSize;
78 : #ifdef DEBUG
79 : bool initialized; // true if this is initialized, use for debug builds
80 : #endif
81 : bool shouldReportOOM; // whether to report OOM to the context
82 : char* base; // malloc'd buffer address
83 : size_t size; // size of buffer allocated at base
84 : ptrdiff_t offset; // offset of next free char in buffer
85 :
86 : MOZ_MUST_USE bool realloc_(size_t newSize);
87 :
88 : public:
89 : explicit Sprinter(JSContext* cx, bool shouldReportOOM = true);
90 : ~Sprinter();
91 :
92 : // Initialize this sprinter, returns false on error.
93 : MOZ_MUST_USE bool init();
94 :
95 : void checkInvariants() const;
96 :
97 0 : const char* string() const { return base; }
98 2 : const char* stringEnd() const { return base + offset; }
99 : char* release();
100 :
101 : // Returns the string at offset |off|.
102 : char* stringAt(ptrdiff_t off) const;
103 : // Returns the char at offset |off|.
104 : char& operator[](size_t off);
105 :
106 : // Attempt to reserve len + 1 space (for a trailing nullptr byte). If the
107 : // attempt succeeds, return a pointer to the start of that space and adjust the
108 : // internal content. The caller *must* completely fill this space on success.
109 : char* reserve(size_t len);
110 :
111 : // Puts |len| characters from |s| at the current position and
112 : // return true on success, false on failure.
113 : virtual bool put(const char* s, size_t len) override;
114 : using GenericPrinter::put; // pick up |inline bool put(const char* s);|
115 :
116 : // Format the given format/arguments as if by JS_vsmprintf, then put it.
117 : // Return true on success, else return false and report an error (typically
118 : // OOM).
119 : MOZ_MUST_USE bool jsprintf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
120 :
121 : bool putString(JSString* str);
122 :
123 : ptrdiff_t getOffset() const;
124 :
125 : // Report that a string operation failed to get the memory it requested. The
126 : // first call to this function calls JS_ReportOutOfMemory, and sets this
127 : // Sprinter's outOfMemory flag; subsequent calls do nothing.
128 : virtual void reportOutOfMemory() override;
129 : };
130 :
131 : // Fprinter, print a string directly into a file.
132 : class Fprinter final : public GenericPrinter
133 : {
134 : private:
135 : FILE* file_;
136 : bool init_;
137 :
138 : public:
139 : explicit Fprinter(FILE* fp);
140 : Fprinter();
141 : ~Fprinter();
142 :
143 : // Initialize this printer, returns false on error.
144 : MOZ_MUST_USE bool init(const char* path);
145 : void init(FILE* fp);
146 36923 : bool isInitialized() const {
147 36923 : return file_ != nullptr;
148 : }
149 : void flush();
150 : void finish();
151 :
152 : // Puts |len| characters from |s| at the current position and
153 : // return true on success, false on failure.
154 : virtual bool put(const char* s, size_t len) override;
155 : using GenericPrinter::put; // pick up |inline bool put(const char* s);|
156 : };
157 :
158 : // LSprinter, is similar to Sprinter except that instead of using an
159 : // JSContext to allocate strings, it use a LifoAlloc as a backend for the
160 : // allocation of the chunk of the string.
161 0 : class LSprinter final : public GenericPrinter
162 : {
163 : private:
164 : struct Chunk
165 : {
166 : Chunk* next;
167 : size_t length;
168 :
169 0 : char* chars() {
170 0 : return reinterpret_cast<char*>(this + 1);
171 : }
172 0 : char* end() {
173 0 : return chars() + length;
174 : }
175 : };
176 :
177 : private:
178 : LifoAlloc* alloc_; // LifoAlloc used as a backend of chunk allocations.
179 : Chunk* head_;
180 : Chunk* tail_;
181 : size_t unused_;
182 :
183 : public:
184 : explicit LSprinter(LifoAlloc* lifoAlloc);
185 : ~LSprinter();
186 :
187 : // Copy the content of the chunks into another printer, such that we can
188 : // flush the content of this printer to a file.
189 : void exportInto(GenericPrinter& out) const;
190 :
191 : // Drop the current string, and let them be free with the LifoAlloc.
192 : void clear();
193 :
194 : // Puts |len| characters from |s| at the current position and
195 : // return true on success, false on failure.
196 : virtual bool put(const char* s, size_t len) override;
197 : using GenericPrinter::put; // pick up |inline bool put(const char* s);|
198 : };
199 :
200 : // Map escaped code to the letter/symbol escaped with a backslash.
201 : extern const char js_EscapeMap[];
202 :
203 : // Return a GC'ed string containing the chars in str, with any non-printing
204 : // chars or quotes (' or " as specified by the quote argument) escaped, and
205 : // with the quote character at the beginning and end of the result string.
206 : extern JSString*
207 : QuoteString(JSContext* cx, JSString* str, char16_t quote);
208 :
209 : extern char*
210 : QuoteString(Sprinter* sp, JSString* str, char16_t quote);
211 :
212 :
213 : } // namespace js
214 :
215 : #endif // vm_Printer_h
|