1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
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
|