Bug 1334307 - do not allocate in GenericPrinter::vprintf; r?nbp
MozReview-Commit-ID: Ibcv21s3tU0
--- a/js/src/vm/Printer.cpp
+++ b/js/src/vm/Printer.cpp
@@ -2,29 +2,52 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "vm/Printer.h"
#include "mozilla/PodOperations.h"
+#include "mozilla/Printf.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include "jscntxt.h"
-#include "jsprf.h"
#include "jsutil.h"
#include "ds/LifoAlloc.h"
using mozilla::PodCopy;
+namespace
+{
+
+class GenericPrinterPrintfTarget : public mozilla::PrintfTarget
+{
+public:
+
+ explicit GenericPrinterPrintfTarget(js::GenericPrinter& p)
+ : printer(p)
+ {
+ }
+
+ bool append(const char* sp, size_t len) {
+ return printer.put(sp, len);
+ }
+
+private:
+
+ js::GenericPrinter& printer;
+};
+
+}
+
namespace js {
GenericPrinter::GenericPrinter()
: hadOOM_(false)
{
}
void
@@ -53,25 +76,22 @@ GenericPrinter::printf(const char* fmt,
bool
GenericPrinter::vprintf(const char* fmt, va_list ap)
{
// Simple shortcut to avoid allocating strings.
if (strchr(fmt, '%') == nullptr)
return put(fmt);
- char* bp;
- bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */
- if (!bp) {
+ GenericPrinterPrintfTarget printer(*this);
+ if (!printer.vprint(fmt, ap)) {
reportOutOfMemory();
return false;
}
- bool r = put(bp);
- js_free(bp);
- return r;
+ return true;
}
const size_t Sprinter::DefaultSize = 64;
bool
Sprinter::realloc_(size_t newSize)
{
MOZ_ASSERT(newSize > (size_t) offset);
@@ -193,35 +213,16 @@ Sprinter::put(const char* s, size_t len)
js_memcpy(bp, s, len);
}
bp[len] = 0;
return true;
}
bool
-Sprinter::vprintf(const char* fmt, va_list ap)
-{
- InvariantChecker ic(this);
-
- do {
- va_list aq;
- va_copy(aq, ap);
- int i = vsnprintf(base + offset, size - offset, fmt, aq);
- va_end(aq);
- if (i > -1 && (size_t) i < size - offset) {
- offset += i;
- return true;
- }
- } while (realloc_(size * 2));
-
- return false;
-}
-
-bool
Sprinter::putString(JSString* s)
{
InvariantChecker ic(this);
size_t length = s->length();
size_t size = length;
char* buffer = reserve(size);
@@ -259,24 +260,20 @@ Sprinter::reportOutOfMemory()
}
bool
Sprinter::jsprintf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
- UniquePtr<char, JS::FreePolicy> chars(JS_vsmprintf(format, ap)); /* XXX vsaprintf */
+ bool r = vprintf(format, ap);
va_end(ap);
- if (!chars) {
- reportOutOfMemory();
- return false;
- }
- return put(chars.get());
+ return r;
}
const char js_EscapeMap[] = {
'\b', 'b',
'\f', 'f',
'\n', 'n',
'\r', 'r',
'\t', 't',
@@ -447,39 +444,16 @@ Fprinter::put(const char* s, size_t len)
int i = fwrite(s, len, 1, file_);
if (size_t(i) != len) {
reportOutOfMemory();
return false;
}
return true;
}
-bool
-Fprinter::printf(const char* fmt, ...)
-{
- MOZ_ASSERT(file_);
- va_list ap;
- va_start(ap, fmt);
- bool r = vfprintf(file_, fmt, ap);
- if (!r)
- reportOutOfMemory();
- va_end(ap);
- return r;
-}
-
-bool
-Fprinter::vprintf(const char* fmt, va_list ap)
-{
- MOZ_ASSERT(file_);
- bool r = vfprintf(file_, fmt, ap);
- if (!r)
- reportOutOfMemory();
- return r;
-}
-
LSprinter::LSprinter(LifoAlloc* lifoAlloc)
: alloc_(lifoAlloc),
head_(nullptr),
tail_(nullptr),
unused_(0)
{ }
LSprinter::~LSprinter()
@@ -570,44 +544,16 @@ LSprinter::put(const char* s, size_t len
MOZ_ASSERT(unused_ >= overflow);
unused_ -= overflow;
}
MOZ_ASSERT(len <= INT_MAX);
return true;
}
-bool
-LSprinter::printf(const char* fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- bool r = vprintf(fmt, va);
- va_end(va);
- return r;
-}
-
-bool
-LSprinter::vprintf(const char* fmt, va_list ap)
-{
- // Simple shortcut to avoid allocating strings.
- if (strchr(fmt, '%') == nullptr)
- return put(fmt);
-
- char* bp;
- bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */
- if (!bp) {
- reportOutOfMemory();
- return false;
- }
- bool r = put(bp);
- js_free(bp);
- return r;
-}
-
void
LSprinter::reportOutOfMemory()
{
if (hadOOM_)
return;
hadOOM_ = true;
}
--- a/js/src/vm/Printer.h
+++ b/js/src/vm/Printer.h
@@ -39,18 +39,18 @@ class GenericPrinter
// return true on success, false on failure.
virtual bool put(const char* s, size_t len) = 0;
inline bool put(const char* s) {
return put(s, strlen(s));
}
// Prints a formatted string into the buffer.
- virtual bool printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
- virtual bool vprintf(const char* fmt, va_list ap);
+ bool printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
+ bool 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;
@@ -113,19 +113,16 @@ class Sprinter final : public GenericPri
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);
- // Prints a formatted string into the buffer.
- virtual bool vprintf(const char* fmt, va_list ap) override;
-
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;
@@ -151,20 +148,16 @@ class Fprinter final : public GenericPri
}
void flush();
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);|
-
- // Prints a formatted string into the buffer.
- virtual bool printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
- virtual bool vprintf(const char* fmt, va_list ap) override;
};
// 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:
@@ -198,20 +191,16 @@ class LSprinter final : public GenericPr
// 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);|
- // Prints a formatted string into the buffer.
- virtual bool printf(const char* fmt, ...) override MOZ_FORMAT_PRINTF(2, 3);
- virtual bool 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;
};