summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Printer.h
blob: 60f1a6271643a3127a6981a85e7d2e0b1d197965 (plain)
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * 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 <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

class JSString;

namespace js {

class ExclusiveContext;
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 ExclusiveContext or a link-list
// of chunks allocated with a LifoAlloc.
class GenericPrinter
{
  protected:
    bool                  hadOOM_;     // whether reportOutOfMemory() has been called.

    GenericPrinter();

  public:
    // Puts |len| characters from |s| at the current position and return an offset to
    // the beginning of this new data.
    virtual int put(const char* s, size_t len) = 0;

    inline int put(const char* s) {
        return put(s, strlen(s));
    }

    // Prints a formatted string into the buffer.
    virtual int printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
    virtual int vprintf(const char* fmt, va_list ap);

    // 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();

    // 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();
        }
    };

    ExclusiveContext*     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(ExclusiveContext* cx, bool shouldReportOOM = true);
    ~Sprinter();

    // Initialize this sprinter, returns false on error.
    MOZ_MUST_USE bool init();

    void checkInvariants() const;

    const char* string() const;
    const char* stringEnd() const;
    // 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 an offset to
    // the beginning of this new data.
    virtual int put(const char* s, size_t len) override;
    using GenericPrinter::put; // pick up |inline int 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);

    // Prints a formatted string into the buffer.
    virtual int vprintf(const char* fmt, va_list ap) override;

    int 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);
    Fprinter();
    ~Fprinter();

    // 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();
    void finish();

    // Puts |len| characters from |s| at the current position and return an
    // offset to the beginning of this new data.
    virtual int put(const char* s, size_t len) override;
    using GenericPrinter::put; // pick up |inline int put(const char* s);|

    // Prints a formatted string into the buffer.
    virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
    virtual int vprintf(const char* fmt, va_list ap) override;
};

// LSprinter, is similar to Sprinter except that instead of using an
// ExclusiveContext 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 an
    // offset to the beginning of this new data.
    virtual int put(const char* s, size_t len) override;
    using GenericPrinter::put; // pick up |inline int put(const char* s);|

    // Prints a formatted string into the buffer.
    virtual int printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
    virtual int vprintf(const char* fmt, va_list ap) override;

    // 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;

    // Return true if this Sprinter ran out of memory.
    virtual bool hadOutOfMemory() const override;
};

// Map escaped code to the letter/symbol escaped with a backslash.
extern const char       js_EscapeMap[];

// Return a GC'ed string containing the chars in str, with any non-printing
// chars or quotes (' or " as specified by the quote argument) escaped, and
// with the quote character at the beginning and end of the result string.
extern JSString*
QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote);

extern char*
QuoteString(Sprinter* sp, JSString* str, char16_t quote);


} // namespace js

#endif // vm_Printer_h