DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
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
/* -*- 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 <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include "js/TypeDecls.h"
#include "js/Utility.h"

namespace js {

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');

// 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 JSON quoted string to the given Sprinter.
extern bool JSONQuoteString(Sprinter* sp, JSString* str);

}  // namespace js

#endif  // vm_Printer_h