--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -3580,17 +3580,18 @@ static bool
DumpStringRepresentation(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedString str(cx, ToString(cx, args.get(0)));
if (!str)
return false;
- str->dumpRepresentation(stderr, 0);
+ Fprinter out(stderr);
+ str->dumpRepresentation(out, 0);
args.rval().setUndefined();
return true;
}
#endif
static bool
SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -618,250 +618,257 @@ ParseNode::appendOrCreateList(ParseNodeK
static const char * const parseNodeNames[] = {
#define STRINGIFY(name) #name,
FOR_EACH_PARSE_NODE_KIND(STRINGIFY)
#undef STRINGIFY
};
void
-frontend::DumpParseTree(ParseNode* pn, int indent)
+frontend::DumpParseTree(ParseNode* pn, GenericPrinter& out, int indent)
{
if (pn == nullptr)
- fprintf(stderr, "#NULL");
+ out.put("#NULL");
else
- pn->dump(indent);
+ pn->dump(out, indent);
}
static void
-IndentNewLine(int indent)
+IndentNewLine(GenericPrinter& out, int indent)
{
- fputc('\n', stderr);
+ out.putChar('\n');
for (int i = 0; i < indent; ++i)
- fputc(' ', stderr);
+ out.putChar(' ');
+}
+
+void
+ParseNode::dump(GenericPrinter& out)
+{
+ dump(out, 0);
+ out.putChar('\n');
}
void
ParseNode::dump()
{
- dump(0);
- fputc('\n', stderr);
+ js::Fprinter out(stderr);
+ dump(out);
}
void
-ParseNode::dump(int indent)
+ParseNode::dump(GenericPrinter& out, int indent)
{
switch (pn_arity) {
case PN_NULLARY:
- ((NullaryNode*) this)->dump();
+ ((NullaryNode*) this)->dump(out);
break;
case PN_UNARY:
- ((UnaryNode*) this)->dump(indent);
+ ((UnaryNode*) this)->dump(out, indent);
break;
case PN_BINARY:
- ((BinaryNode*) this)->dump(indent);
+ ((BinaryNode*) this)->dump(out, indent);
break;
case PN_TERNARY:
- ((TernaryNode*) this)->dump(indent);
+ ((TernaryNode*) this)->dump(out, indent);
break;
case PN_CODE:
- ((CodeNode*) this)->dump(indent);
+ ((CodeNode*) this)->dump(out, indent);
break;
case PN_LIST:
- ((ListNode*) this)->dump(indent);
+ ((ListNode*) this)->dump(out, indent);
break;
case PN_NAME:
- ((NameNode*) this)->dump(indent);
+ ((NameNode*) this)->dump(out, indent);
break;
case PN_SCOPE:
- ((LexicalScopeNode*) this)->dump(indent);
+ ((LexicalScopeNode*) this)->dump(out, indent);
break;
default:
- fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>",
+ out.printf("#<BAD NODE %p, kind=%u, arity=%u>",
(void*) this, unsigned(getKind()), unsigned(pn_arity));
break;
}
}
void
-NullaryNode::dump()
+NullaryNode::dump(GenericPrinter& out)
{
switch (getKind()) {
- case PNK_TRUE: fprintf(stderr, "#true"); break;
- case PNK_FALSE: fprintf(stderr, "#false"); break;
- case PNK_NULL: fprintf(stderr, "#null"); break;
- case PNK_RAW_UNDEFINED: fprintf(stderr, "#undefined"); break;
+ case PNK_TRUE: out.put("#true"); break;
+ case PNK_FALSE: out.put("#false"); break;
+ case PNK_NULL: out.put("#null"); break;
+ case PNK_RAW_UNDEFINED: out.put("#undefined"); break;
case PNK_NUMBER: {
ToCStringBuf cbuf;
const char* cstr = NumberToCString(nullptr, &cbuf, pn_dval);
if (!IsFinite(pn_dval))
- fputc('#', stderr);
+ out.put("#");
if (cstr)
- fprintf(stderr, "%s", cstr);
+ out.printf("%s", cstr);
else
- fprintf(stderr, "%g", pn_dval);
+ out.printf("%g", pn_dval);
break;
}
case PNK_STRING:
- pn_atom->dumpCharsNoNewline();
+ pn_atom->dumpCharsNoNewline(out);
break;
default:
- fprintf(stderr, "(%s)", parseNodeNames[getKind()]);
+ out.printf("(%s)", parseNodeNames[getKind()]);
}
}
void
-UnaryNode::dump(int indent)
+UnaryNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s ", name);
+ out.printf("(%s ", name);
indent += strlen(name) + 2;
- DumpParseTree(pn_kid, indent);
- fprintf(stderr, ")");
+ DumpParseTree(pn_kid, out, indent);
+ out.printf(")");
}
void
-BinaryNode::dump(int indent)
+BinaryNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s ", name);
+ out.printf("(%s ", name);
indent += strlen(name) + 2;
- DumpParseTree(pn_left, indent);
- IndentNewLine(indent);
- DumpParseTree(pn_right, indent);
- fprintf(stderr, ")");
+ DumpParseTree(pn_left, out, indent);
+ IndentNewLine(out, indent);
+ DumpParseTree(pn_right, out, indent);
+ out.printf(")");
}
void
-TernaryNode::dump(int indent)
+TernaryNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s ", name);
+ out.printf("(%s ", name);
indent += strlen(name) + 2;
- DumpParseTree(pn_kid1, indent);
- IndentNewLine(indent);
- DumpParseTree(pn_kid2, indent);
- IndentNewLine(indent);
- DumpParseTree(pn_kid3, indent);
- fprintf(stderr, ")");
+ DumpParseTree(pn_kid1, out, indent);
+ IndentNewLine(out, indent);
+ DumpParseTree(pn_kid2, out, indent);
+ IndentNewLine(out, indent);
+ DumpParseTree(pn_kid3, out, indent);
+ out.printf(")");
}
void
-CodeNode::dump(int indent)
+CodeNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s ", name);
+ out.printf("(%s ", name);
indent += strlen(name) + 2;
- DumpParseTree(pn_body, indent);
- fprintf(stderr, ")");
+ DumpParseTree(pn_body, out, indent);
+ out.printf(")");
}
void
-ListNode::dump(int indent)
+ListNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s [", name);
+ out.printf("(%s [", name);
if (pn_head != nullptr) {
indent += strlen(name) + 3;
- DumpParseTree(pn_head, indent);
+ DumpParseTree(pn_head, out, indent);
ParseNode* pn = pn_head->pn_next;
while (pn != nullptr) {
- IndentNewLine(indent);
- DumpParseTree(pn, indent);
+ IndentNewLine(out, indent);
+ DumpParseTree(pn, out, indent);
pn = pn->pn_next;
}
}
- fprintf(stderr, "])");
+ out.printf("])");
}
template <typename CharT>
static void
-DumpName(const CharT* s, size_t len)
+DumpName(GenericPrinter& out, const CharT* s, size_t len)
{
if (len == 0)
- fprintf(stderr, "#<zero-length name>");
+ out.put("#<zero-length name>");
for (size_t i = 0; i < len; i++) {
char16_t c = s[i];
if (c > 32 && c < 127)
fputc(c, stderr);
else if (c <= 255)
- fprintf(stderr, "\\x%02x", unsigned(c));
+ out.printf("\\x%02x", unsigned(c));
else
- fprintf(stderr, "\\u%04x", unsigned(c));
+ out.printf("\\u%04x", unsigned(c));
}
}
void
-NameNode::dump(int indent)
+NameNode::dump(GenericPrinter& out, int indent)
{
if (isKind(PNK_NAME) || isKind(PNK_DOT)) {
if (isKind(PNK_DOT))
- fprintf(stderr, "(.");
+ out.put("(.");
if (!pn_atom) {
- fprintf(stderr, "#<null name>");
+ out.put("#<null name>");
} else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
// Dump destructuring parameter.
- fprintf(stderr, "(#<zero-length name> ");
- DumpParseTree(expr(), indent + 21);
- fputc(')', stderr);
+ out.put("(#<zero-length name> ");
+ DumpParseTree(expr(), out, indent + 21);
+ out.printf(")");
} else {
JS::AutoCheckCannotGC nogc;
if (pn_atom->hasLatin1Chars())
- DumpName(pn_atom->latin1Chars(nogc), pn_atom->length());
+ DumpName(out, pn_atom->latin1Chars(nogc), pn_atom->length());
else
- DumpName(pn_atom->twoByteChars(nogc), pn_atom->length());
+ DumpName(out, pn_atom->twoByteChars(nogc), pn_atom->length());
}
if (isKind(PNK_DOT)) {
- fputc(' ', stderr);
+ out.putChar(' ');
if (as<PropertyAccess>().isSuper())
- fprintf(stderr, "super");
+ out.put("super");
else
- DumpParseTree(expr(), indent + 2);
- fputc(')', stderr);
+ DumpParseTree(expr(), out, indent + 2);
+ out.printf(")");
}
return;
}
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s ", name);
+ out.printf("(%s ", name);
indent += strlen(name) + 2;
- DumpParseTree(expr(), indent);
- fprintf(stderr, ")");
+ DumpParseTree(expr(), out, indent);
+ out.printf(")");
}
void
-LexicalScopeNode::dump(int indent)
+LexicalScopeNode::dump(GenericPrinter& out, int indent)
{
const char* name = parseNodeNames[getKind()];
- fprintf(stderr, "(%s [", name);
+ out.printf("(%s [", name);
int nameIndent = indent + strlen(name) + 3;
if (!isEmptyScope()) {
LexicalScope::Data* bindings = scopeBindings();
for (uint32_t i = 0; i < bindings->length; i++) {
JSAtom* name = bindings->names[i].name();
JS::AutoCheckCannotGC nogc;
if (name->hasLatin1Chars())
- DumpName(name->latin1Chars(nogc), name->length());
+ DumpName(out, name->latin1Chars(nogc), name->length());
else
- DumpName(name->twoByteChars(nogc), name->length());
+ DumpName(out, name->twoByteChars(nogc), name->length());
if (i < bindings->length - 1)
- IndentNewLine(nameIndent);
+ IndentNewLine(out, nameIndent);
}
}
- fprintf(stderr, "]");
+ out.putChar(']');
indent += 2;
- IndentNewLine(indent);
- DumpParseTree(scopeBody(), indent);
- fprintf(stderr, ")");
+ IndentNewLine(out, indent);
+ DumpParseTree(scopeBody(), out, indent);
+ out.printf(")");
}
#endif
ObjectBox::ObjectBox(JSObject* object, ObjectBox* traceLink)
: object(object),
traceLink(traceLink),
emitLink(nullptr)
{
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -6,16 +6,17 @@
#ifndef frontend_ParseNode_h
#define frontend_ParseNode_h
#include "mozilla/Attributes.h"
#include "builtin/ModuleObject.h"
#include "frontend/TokenStream.h"
+#include "vm/Printer.h"
namespace js {
namespace frontend {
class ParseContext;
class FullParseHandler;
class FunctionBox;
class ObjectBox;
@@ -813,18 +814,20 @@ class ParseNode
template <class NodeType>
inline const NodeType& as() const {
MOZ_ASSERT(NodeType::test(*this));
return *static_cast<const NodeType*>(this);
}
#ifdef DEBUG
+ // Debugger-friendly stderr printer.
void dump();
- void dump(int indent);
+ void dump(GenericPrinter& out);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct NullaryNode : public ParseNode
{
NullaryNode(ParseNodeKind kind, const TokenPos& pos)
: ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {}
NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
@@ -835,30 +838,30 @@ struct NullaryNode : public ParseNode
// that nullary nodes shouldn't use -- bogus.
NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, JSAtom* atom)
: ParseNode(kind, op, PN_NULLARY, pos)
{
pn_atom = atom;
}
#ifdef DEBUG
- void dump();
+ void dump(GenericPrinter& out);
#endif
};
struct UnaryNode : public ParseNode
{
UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* kid)
: ParseNode(kind, op, PN_UNARY, pos)
{
pn_kid = kid;
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct BinaryNode : public ParseNode
{
BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos& pos, ParseNode* left, ParseNode* right)
: ParseNode(kind, op, PN_BINARY, pos)
{
@@ -869,17 +872,17 @@ struct BinaryNode : public ParseNode
BinaryNode(ParseNodeKind kind, JSOp op, ParseNode* left, ParseNode* right)
: ParseNode(kind, op, PN_BINARY, TokenPos::box(left->pn_pos, right->pn_pos))
{
pn_left = left;
pn_right = right;
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct TernaryNode : public ParseNode
{
TernaryNode(ParseNodeKind kind, JSOp op, ParseNode* kid1, ParseNode* kid2, ParseNode* kid3)
: ParseNode(kind, op, PN_TERNARY,
TokenPos((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin,
@@ -895,17 +898,17 @@ struct TernaryNode : public ParseNode
: ParseNode(kind, op, PN_TERNARY, pos)
{
pn_kid1 = kid1;
pn_kid2 = kid2;
pn_kid3 = kid3;
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct ListNode : public ParseNode
{
ListNode(ParseNodeKind kind, const TokenPos& pos)
: ParseNode(kind, JSOP_NOP, PN_LIST, pos)
{
@@ -924,17 +927,17 @@ struct ListNode : public ParseNode
initList(kid);
}
static bool test(const ParseNode& node) {
return node.isArity(PN_LIST);
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct CodeNode : public ParseNode
{
CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos)
: ParseNode(kind, op, PN_CODE, pos)
{
@@ -944,31 +947,31 @@ struct CodeNode : public ParseNode
op == JSOP_LAMBDA_ARROW || // arrow function
op == JSOP_LAMBDA); // expression, method, comprehension, accessor, &c.
MOZ_ASSERT(!pn_body);
MOZ_ASSERT(!pn_objbox);
}
public:
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct NameNode : public ParseNode
{
NameNode(ParseNodeKind kind, JSOp op, JSAtom* atom, const TokenPos& pos)
: ParseNode(kind, op, PN_NAME, pos)
{
pn_atom = atom;
pn_expr = nullptr;
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
struct LexicalScopeNode : public ParseNode
{
LexicalScopeNode(LexicalScope::Data* bindings, ParseNode* body)
: ParseNode(PNK_LEXICALSCOPE, JSOP_NOP, PN_SCOPE, body->pn_pos)
{
@@ -976,17 +979,17 @@ struct LexicalScopeNode : public ParseNo
pn_u.scope.body = body;
}
static bool test(const ParseNode& node) {
return node.isKind(PNK_LEXICALSCOPE);
}
#ifdef DEBUG
- void dump(int indent);
+ void dump(GenericPrinter& out, int indent);
#endif
};
class LabeledStatement : public ParseNode
{
public:
LabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin)
: ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos(begin, stmt->pn_pos.end))
@@ -1347,17 +1350,17 @@ struct ClassNode : public TernaryNode {
}
Handle<LexicalScope::Data*> scopeBindings() const {
MOZ_ASSERT(pn_kid3->is<LexicalScopeNode>());
return pn_kid3->scopeBindings();
}
};
#ifdef DEBUG
-void DumpParseTree(ParseNode* pn, int indent = 0);
+void DumpParseTree(ParseNode* pn, GenericPrinter& out, int indent = 0);
#endif
class ParseNodeAllocator
{
public:
explicit ParseNodeAllocator(JSContext* cx, LifoAlloc& alloc)
: cx(cx), alloc(alloc), freelist(nullptr)
{}
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -25,16 +25,18 @@
#include "ds/BitArray.h"
#include "gc/Memory.h"
#include "js/GCAPI.h"
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
+#include "vm/Printer.h"
+
struct JSRuntime;
namespace js {
class AutoLockGC;
class FreeOp;
extern bool
@@ -273,17 +275,17 @@ struct Cell
inline StoreBuffer* storeBuffer() const;
inline JS::TraceKind getTraceKind() const;
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
#ifdef DEBUG
inline bool isAligned() const;
- void dump(FILE* fp) const;
+ void dump(js::GenericPrinter& out) const;
void dump() const;
#endif
protected:
inline uintptr_t address() const;
inline Chunk* chunk() const;
} JS_HAZ_GC_THING;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -658,44 +658,113 @@ JS_CloneObject(JSContext* cx, HandleObje
// |obj| might be in a different compartment.
assertSameCompartment(cx, protoArg);
Rooted<TaggedProto> proto(cx, TaggedProto(protoArg.get()));
return CloneObject(cx, obj, proto);
}
#ifdef DEBUG
+// We don't want jsfriendapi.h to depend on GenericPrinter,
+// so these functions are declared directly in the cpp.
+
+namespace js {
+
+extern JS_FRIEND_API(void)
+DumpString(JSString* str, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpAtom(JSAtom* atom, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpObject(JSObject* obj, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpChars(const char16_t* s, size_t n, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpValue(const JS::Value& val, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpId(jsid id, js::GenericPrinter& out);
+
+extern JS_FRIEND_API(void)
+DumpInterpreterFrame(JSContext* cx, js::GenericPrinter& out, InterpreterFrame* start = nullptr);
+
+} // namespace js
+
+JS_FRIEND_API(void)
+js::DumpString(JSString* str, js::GenericPrinter& out)
+{
+ str->dump(out);
+}
+
+JS_FRIEND_API(void)
+js::DumpAtom(JSAtom* atom, js::GenericPrinter& out)
+{
+ atom->dump(out);
+}
+
+JS_FRIEND_API(void)
+js::DumpChars(const char16_t* s, size_t n, js::GenericPrinter& out)
+{
+ out.printf("char16_t * (%p) = ", (void*) s);
+ JSString::dumpChars(s, n, out);
+ out.putChar('\n');
+}
+
+JS_FRIEND_API(void)
+js::DumpObject(JSObject* obj, js::GenericPrinter& out)
+{
+ if (!obj) {
+ out.printf("NULL\n");
+ return;
+ }
+ obj->dump(out);
+}
+
JS_FRIEND_API(void)
js::DumpString(JSString* str, FILE* fp)
{
- str->dump(fp);
+ Fprinter out(fp);
+ js::DumpString(str, out);
}
JS_FRIEND_API(void)
js::DumpAtom(JSAtom* atom, FILE* fp)
{
- atom->dump(fp);
+ Fprinter out(fp);
+ js::DumpAtom(atom, out);
}
JS_FRIEND_API(void)
js::DumpChars(const char16_t* s, size_t n, FILE* fp)
{
- fprintf(fp, "char16_t * (%p) = ", (void*) s);
- JSString::dumpChars(s, n, fp);
- fputc('\n', fp);
+ Fprinter out(fp);
+ js::DumpChars(s, n, out);
}
JS_FRIEND_API(void)
js::DumpObject(JSObject* obj, FILE* fp)
{
- if (!obj) {
- fprintf(fp, "NULL\n");
- return;
- }
- obj->dump(fp);
+ Fprinter out(fp);
+ js::DumpObject(obj, out);
+}
+
+JS_FRIEND_API(void)
+js::DumpId(jsid id, FILE* fp)
+{
+ Fprinter out(fp);
+ js::DumpId(id, out);
+}
+
+JS_FRIEND_API(void)
+js::DumpValue(const JS::Value& val, FILE* fp) {
+ Fprinter out(fp);
+ js::DumpValue(val, out);
}
JS_FRIEND_API(void)
js::DumpString(JSString* str) {
DumpString(str, stderr);
}
JS_FRIEND_API(void)
js::DumpAtom(JSAtom* atom) {
@@ -715,17 +784,18 @@ js::DumpValue(const JS::Value& val) {
}
JS_FRIEND_API(void)
js::DumpId(jsid id) {
DumpId(id, stderr);
}
JS_FRIEND_API(void)
js::DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start)
{
- DumpInterpreterFrame(cx, stderr, start);
+ Fprinter out(stderr);
+ DumpInterpreterFrame(cx, out, start);
}
JS_FRIEND_API(bool)
js::DumpPC(JSContext* cx) {
return DumpPC(cx, stdout);
}
JS_FRIEND_API(bool)
js::DumpScript(JSContext* cx, JSScript* scriptArg)
{
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -229,16 +229,17 @@
#include "gc/Policy.h"
#include "jit/BaselineJIT.h"
#include "jit/IonCode.h"
#include "jit/JitcodeMap.h"
#include "js/SliceBudget.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/Debugger.h"
#include "vm/GeckoProfiler.h"
+#include "vm/Printer.h"
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
#include "vm/String.h"
#include "vm/Symbol.h"
#include "vm/Time.h"
#include "vm/TraceLogging.h"
#include "vm/WrapperObject.h"
@@ -8734,42 +8735,54 @@ AutoEmptyNursery::AutoEmptyNursery(JSCon
cx->runtime()->gc.stats().resumePhases();
checkCondition(cx);
}
} /* namespace gc */
} /* namespace js */
#ifdef DEBUG
-void
-js::gc::Cell::dump(FILE* fp) const
+
+namespace js {
+
+// We don't want jsfriendapi.h to depend on GenericPrinter,
+// so these functions are declared directly in the cpp.
+
+extern JS_FRIEND_API(void)
+DumpString(JSString* str, js::GenericPrinter& out);
+
+}
+
+void
+js::gc::Cell::dump(js::GenericPrinter& out) const
{
switch (getTraceKind()) {
case JS::TraceKind::Object:
- reinterpret_cast<const JSObject*>(this)->dump(fp);
+ reinterpret_cast<const JSObject*>(this)->dump(out);
break;
case JS::TraceKind::String:
- js::DumpString(reinterpret_cast<JSString*>(const_cast<Cell*>(this)), fp);
+ js::DumpString(reinterpret_cast<JSString*>(const_cast<Cell*>(this)), out);
break;
case JS::TraceKind::Shape:
- reinterpret_cast<const Shape*>(this)->dump(fp);
+ reinterpret_cast<const Shape*>(this)->dump(out);
break;
default:
- fprintf(fp, "%s(%p)\n", JS::GCTraceKindToAscii(getTraceKind()), (void*) this);
+ out.printf("%s(%p)\n", JS::GCTraceKindToAscii(getTraceKind()), (void*) this);
}
}
// For use in a debugger.
void
js::gc::Cell::dump() const
{
- dump(stderr);
+ js::Fprinter out(stderr);
+ dump(out);
}
#endif
static inline bool
CanCheckGrayBits(const Cell* cell)
{
MOZ_ASSERT(cell);
if (!cell->isTenured())
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3356,345 +3356,379 @@ GetObjectSlotNameFunctor::operator()(JS:
/*
* Routines to print out values during debugging. These are FRIEND_API to help
* the debugger find them and to support temporarily hacking js::Dump* calls
* into other code.
*/
static void
-dumpValue(const Value& v, FILE* fp)
+dumpValue(const Value& v, js::GenericPrinter& out)
{
if (v.isNull())
- fprintf(fp, "null");
+ out.put("null");
else if (v.isUndefined())
- fprintf(fp, "undefined");
+ out.put("undefined");
else if (v.isInt32())
- fprintf(fp, "%d", v.toInt32());
+ out.printf("%d", v.toInt32());
else if (v.isDouble())
- fprintf(fp, "%g", v.toDouble());
+ out.printf("%g", v.toDouble());
else if (v.isString())
- v.toString()->dump(fp);
+ v.toString()->dump(out);
else if (v.isSymbol())
- v.toSymbol()->dump(fp);
+ v.toSymbol()->dump(out);
else if (v.isObject() && v.toObject().is<JSFunction>()) {
JSFunction* fun = &v.toObject().as<JSFunction>();
if (fun->displayAtom()) {
- fputs("<function ", fp);
- FileEscapedString(fp, fun->displayAtom(), 0);
+ out.put("<function ");
+ EscapedStringPrinter(out, fun->displayAtom(), 0);
} else {
- fputs("<unnamed function", fp);
+ out.put("<unnamed function");
}
if (fun->hasScript()) {
JSScript* script = fun->nonLazyScript();
- fprintf(fp, " (%s:%zu)",
+ out.printf(" (%s:%zu)",
script->filename() ? script->filename() : "", script->lineno());
}
- fprintf(fp, " at %p>", (void*) fun);
+ out.printf(" at %p>", (void*) fun);
} else if (v.isObject()) {
JSObject* obj = &v.toObject();
const Class* clasp = obj->getClass();
- fprintf(fp, "<%s%s at %p>",
+ out.printf("<%s%s at %p>",
clasp->name,
(clasp == &PlainObject::class_) ? "" : " object",
(void*) obj);
} else if (v.isBoolean()) {
if (v.toBoolean())
- fprintf(fp, "true");
+ out.put("true");
else
- fprintf(fp, "false");
+ out.put("false");
} else if (v.isMagic()) {
- fprintf(fp, "<invalid");
+ out.put("<invalid");
#ifdef DEBUG
switch (v.whyMagic()) {
- case JS_ELEMENTS_HOLE: fprintf(fp, " elements hole"); break;
- case JS_NO_ITER_VALUE: fprintf(fp, " no iter value"); break;
- case JS_GENERATOR_CLOSING: fprintf(fp, " generator closing"); break;
- case JS_OPTIMIZED_OUT: fprintf(fp, " optimized out"); break;
- default: fprintf(fp, " ?!"); break;
+ case JS_ELEMENTS_HOLE: out.put(" elements hole"); break;
+ case JS_NO_ITER_VALUE: out.put(" no iter value"); break;
+ case JS_GENERATOR_CLOSING: out.put(" generator closing"); break;
+ case JS_OPTIMIZED_OUT: out.put(" optimized out"); break;
+ default: out.put(" ?!"); break;
}
#endif
- fprintf(fp, ">");
+ out.putChar('>');
} else {
- fprintf(fp, "unexpected value");
+ out.put("unexpected value");
}
}
+namespace js {
+
+// We don't want jsfriendapi.h to depend on GenericPrinter,
+// so these functions are declared directly in the cpp.
+
+JS_FRIEND_API(void)
+DumpValue(const JS::Value& val, js::GenericPrinter& out);
+
+JS_FRIEND_API(void)
+DumpId(jsid id, js::GenericPrinter& out);
+
+JS_FRIEND_API(void)
+DumpInterpreterFrame(JSContext* cx, js::GenericPrinter& out, InterpreterFrame* start = nullptr);
+
+} // namespace js
+
+JS_FRIEND_API(void)
+js::DumpValue(const Value& val, js::GenericPrinter& out)
+{
+ dumpValue(val, out);
+ out.putChar('\n');
+}
+
JS_FRIEND_API(void)
-js::DumpValue(const Value& val, FILE* fp)
+js::DumpId(jsid id, js::GenericPrinter& out)
{
- dumpValue(val, fp);
- fputc('\n', fp);
-}
-
-JS_FRIEND_API(void)
-js::DumpId(jsid id, FILE* fp)
-{
- fprintf(fp, "jsid %p = ", (void*) JSID_BITS(id));
- dumpValue(IdToValue(id), fp);
- fputc('\n', fp);
+ out.printf("jsid %p = ", (void*) JSID_BITS(id));
+ dumpValue(IdToValue(id), out);
+ out.putChar('\n');
}
static void
-DumpProperty(const NativeObject* obj, Shape& shape, FILE* fp)
+DumpProperty(const NativeObject* obj, Shape& shape, js::GenericPrinter& out)
{
jsid id = shape.propid();
uint8_t attrs = shape.attributes();
- fprintf(fp, " ((js::Shape*) %p) ", (void*) &shape);
- if (attrs & JSPROP_ENUMERATE) fprintf(fp, "enumerate ");
- if (attrs & JSPROP_READONLY) fprintf(fp, "readonly ");
- if (attrs & JSPROP_PERMANENT) fprintf(fp, "permanent ");
- if (attrs & JSPROP_SHARED) fprintf(fp, "shared ");
+ out.printf(" ((js::Shape*) %p) ", (void*) &shape);
+ if (attrs & JSPROP_ENUMERATE) out.put("enumerate ");
+ if (attrs & JSPROP_READONLY) out.put("readonly ");
+ if (attrs & JSPROP_PERMANENT) out.put("permanent ");
+ if (attrs & JSPROP_SHARED) out.put("shared ");
if (shape.hasGetterValue())
- fprintf(fp, "getterValue=%p ", (void*) shape.getterObject());
+ out.printf("getterValue=%p ", (void*) shape.getterObject());
else if (!shape.hasDefaultGetter())
- fprintf(fp, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.getterOp()));
+ out.printf("getterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.getterOp()));
if (shape.hasSetterValue())
- fprintf(fp, "setterValue=%p ", (void*) shape.setterObject());
+ out.printf("setterValue=%p ", (void*) shape.setterObject());
else if (!shape.hasDefaultSetter())
- fprintf(fp, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.setterOp()));
+ out.printf("setterOp=%p ", JS_FUNC_TO_DATA_PTR(void*, shape.setterOp()));
if (JSID_IS_ATOM(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id))
- dumpValue(js::IdToValue(id), fp);
+ dumpValue(js::IdToValue(id), out);
else
- fprintf(fp, "unknown jsid %p", (void*) JSID_BITS(id));
+ out.printf("unknown jsid %p", (void*) JSID_BITS(id));
uint32_t slot = shape.hasSlot() ? shape.maybeSlot() : SHAPE_INVALID_SLOT;
- fprintf(fp, ": slot %d", slot);
+ out.printf(": slot %d", slot);
if (shape.hasSlot()) {
- fprintf(fp, " = ");
- dumpValue(obj->getSlot(slot), fp);
+ out.put(" = ");
+ dumpValue(obj->getSlot(slot), out);
} else if (slot != SHAPE_INVALID_SLOT) {
- fprintf(fp, " (INVALID!)");
+ out.printf(" (INVALID!)");
}
- fprintf(fp, "\n");
+ out.putChar('\n');
}
bool
JSObject::uninlinedIsProxy() const
{
return is<ProxyObject>();
}
bool
JSObject::uninlinedNonProxyIsExtensible() const
{
return nonProxyIsExtensible();
}
void
-JSObject::dump(FILE* fp) const
+JSObject::dump(js::GenericPrinter& out) const
{
const JSObject* obj = this;
JSObject* globalObj = &global();
- fprintf(fp, "object %p from global %p [%s]\n", (void*) obj,
+ out.printf("object %p from global %p [%s]\n", (void*) obj,
(void*) globalObj, globalObj->getClass()->name);
const Class* clasp = obj->getClass();
- fprintf(fp, "class %p %s\n", (const void*)clasp, clasp->name);
+ out.printf("class %p %s\n", (const void*)clasp, clasp->name);
if (obj->hasLazyGroup()) {
- fprintf(fp, "lazy group\n");
+ out.put("lazy group\n");
} else {
const ObjectGroup* group = obj->group();
- fprintf(fp, "group %p\n", (const void*)group);
+ out.printf("group %p\n", (const void*)group);
}
- fprintf(fp, "flags:");
- if (obj->isDelegate()) fprintf(fp, " delegate");
- if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) fprintf(fp, " not_extensible");
- if (obj->isIndexed()) fprintf(fp, " indexed");
- if (obj->maybeHasInterestingSymbolProperty()) fprintf(fp, " maybe_has_interesting_symbol");
- if (obj->isBoundFunction()) fprintf(fp, " bound_function");
- if (obj->isQualifiedVarObj()) fprintf(fp, " varobj");
- if (obj->isUnqualifiedVarObj()) fprintf(fp, " unqualified_varobj");
- if (obj->watched()) fprintf(fp, " watched");
- if (obj->isIteratedSingleton()) fprintf(fp, " iterated_singleton");
- if (obj->isNewGroupUnknown()) fprintf(fp, " new_type_unknown");
- if (obj->hasUncacheableProto()) fprintf(fp, " has_uncacheable_proto");
- if (obj->hadElementsAccess()) fprintf(fp, " had_elements_access");
- if (obj->wasNewScriptCleared()) fprintf(fp, " new_script_cleared");
+ out.put("flags:");
+ if (obj->isDelegate()) out.put(" delegate");
+ if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) out.put(" not_extensible");
+ if (obj->isIndexed()) out.put(" indexed");
+ if (obj->maybeHasInterestingSymbolProperty()) out.put(" maybe_has_interesting_symbol");
+ if (obj->isBoundFunction()) out.put(" bound_function");
+ if (obj->isQualifiedVarObj()) out.put(" varobj");
+ if (obj->isUnqualifiedVarObj()) out.put(" unqualified_varobj");
+ if (obj->watched()) out.put(" watched");
+ if (obj->isIteratedSingleton()) out.put(" iterated_singleton");
+ if (obj->isNewGroupUnknown()) out.put(" new_type_unknown");
+ if (obj->hasUncacheableProto()) out.put(" has_uncacheable_proto");
+ if (obj->hadElementsAccess()) out.put(" had_elements_access");
+ if (obj->wasNewScriptCleared()) out.put(" new_script_cleared");
if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable())
- fprintf(fp, " immutable_prototype");
+ out.put(" immutable_prototype");
if (obj->isNative()) {
const NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->inDictionaryMode())
- fprintf(fp, " inDictionaryMode");
+ out.put(" inDictionaryMode");
if (nobj->hasShapeTable())
- fprintf(fp, " hasShapeTable");
+ out.put(" hasShapeTable");
}
- fprintf(fp, "\n");
+ out.putChar('\n');
if (obj->isNative()) {
const NativeObject* nobj = &obj->as<NativeObject>();
uint32_t slots = nobj->getDenseInitializedLength();
if (slots) {
- fprintf(fp, "elements\n");
+ out.put("elements\n");
for (uint32_t i = 0; i < slots; i++) {
- fprintf(fp, " %3d: ", i);
- dumpValue(nobj->getDenseElement(i), fp);
- fprintf(fp, "\n");
- fflush(fp);
+ out.printf(" %3d: ", i);
+ dumpValue(nobj->getDenseElement(i), out);
+ out.putChar('\n');
+ out.flush();
}
}
}
- fprintf(fp, "proto ");
+ out.put("proto ");
TaggedProto proto = obj->taggedProto();
if (proto.isDynamic())
- fprintf(fp, "<dynamic>");
+ out.put("<dynamic>");
else
- dumpValue(ObjectOrNullValue(proto.toObjectOrNull()), fp);
- fputc('\n', fp);
+ dumpValue(ObjectOrNullValue(proto.toObjectOrNull()), out);
+ out.putChar('\n');
if (clasp->flags & JSCLASS_HAS_PRIVATE)
- fprintf(fp, "private %p\n", obj->as<NativeObject>().getPrivate());
+ out.printf("private %p\n", obj->as<NativeObject>().getPrivate());
if (!obj->isNative())
- fprintf(fp, "not native\n");
+ out.put("not native\n");
uint32_t reservedEnd = JSCLASS_RESERVED_SLOTS(clasp);
uint32_t slots = obj->isNative() ? obj->as<NativeObject>().slotSpan() : 0;
uint32_t stop = obj->isNative() ? reservedEnd : slots;
if (stop > 0)
- fprintf(fp, obj->isNative() ? "reserved slots:\n" : "slots:\n");
+ out.printf(obj->isNative() ? "reserved slots:\n" : "slots:\n");
for (uint32_t i = 0; i < stop; i++) {
- fprintf(fp, " %3d ", i);
+ out.printf(" %3d ", i);
if (i < reservedEnd)
- fprintf(fp, "(reserved) ");
- fprintf(fp, "= ");
- dumpValue(obj->as<NativeObject>().getSlot(i), fp);
- fputc('\n', fp);
+ out.printf("(reserved) ");
+ out.put("= ");
+ dumpValue(obj->as<NativeObject>().getSlot(i), out);
+ out.putChar('\n');
}
if (obj->isNative()) {
- fprintf(fp, "properties:\n");
+ out.put("properties:\n");
Vector<Shape*, 8, SystemAllocPolicy> props;
for (Shape::Range<NoGC> r(obj->as<NativeObject>().lastProperty()); !r.empty(); r.popFront()) {
if (!props.append(&r.front())) {
- fprintf(fp, "(OOM while appending properties)\n");
+ out.printf("(OOM while appending properties)\n");
break;
}
}
for (size_t i = props.length(); i-- != 0;)
- DumpProperty(&obj->as<NativeObject>(), *props[i], fp);
+ DumpProperty(&obj->as<NativeObject>(), *props[i], out);
}
- fputc('\n', fp);
+ out.putChar('\n');
}
// For debuggers.
void
JSObject::dump() const
{
- dump(stderr);
+ Fprinter out(stderr);
+ dump(out);
}
static void
-MaybeDumpScope(Scope* scope, FILE* fp)
+MaybeDumpScope(Scope* scope, js::GenericPrinter& out)
{
if (scope) {
- fprintf(fp, " scope: %s\n", ScopeKindString(scope->kind()));
+ out.printf(" scope: %s\n", ScopeKindString(scope->kind()));
for (BindingIter bi(scope); bi; bi++) {
- fprintf(fp, " ");
- dumpValue(StringValue(bi.name()), fp);
- fputc('\n', fp);
+ out.put(" ");
+ dumpValue(StringValue(bi.name()), out);
+ out.putChar('\n');
}
}
}
static void
-MaybeDumpValue(const char* name, const Value& v, FILE* fp)
+MaybeDumpValue(const char* name, const Value& v, js::GenericPrinter& out)
{
if (!v.isNull()) {
- fprintf(fp, " %s: ", name);
- dumpValue(v, fp);
- fputc('\n', fp);
+ out.printf(" %s: ", name);
+ dumpValue(v, out);
+ out.putChar('\n');
}
}
JS_FRIEND_API(void)
-js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
+js::DumpInterpreterFrame(JSContext* cx, js::GenericPrinter& out, InterpreterFrame* start)
{
/* This should only called during live debugging. */
ScriptFrameIter i(cx);
if (!start) {
if (i.done()) {
- fprintf(fp, "no stack for cx = %p\n", (void*) cx);
+ out.printf("no stack for cx = %p\n", (void*) cx);
return;
}
} else {
while (!i.done() && !i.isJSJit() && i.interpFrame() != start)
++i;
if (i.done()) {
- fprintf(fp, "fp = %p not found in cx = %p\n",
+ out.printf("fp = %p not found in cx = %p\n",
(void*)start, (void*)cx);
return;
}
}
for (; !i.done(); ++i) {
if (i.isJSJit())
- fprintf(fp, "JIT frame\n");
+ out.put("JIT frame\n");
else
- fprintf(fp, "InterpreterFrame at %p\n", (void*) i.interpFrame());
+ out.printf("InterpreterFrame at %p\n", (void*) i.interpFrame());
if (i.isFunctionFrame()) {
- fprintf(fp, "callee fun: ");
+ out.put("callee fun: ");
RootedValue v(cx);
JSObject* fun = i.callee(cx);
v.setObject(*fun);
- dumpValue(v, fp);
+ dumpValue(v, out);
} else {
- fprintf(fp, "global or eval frame, no callee");
+ out.put("global or eval frame, no callee");
}
- fputc('\n', fp);
-
- fprintf(fp, "file %s line %zu\n",
+ out.putChar('\n');
+
+ out.printf("file %s line %zu\n",
i.script()->filename(), i.script()->lineno());
if (jsbytecode* pc = i.pc()) {
- fprintf(fp, " pc = %p\n", pc);
- fprintf(fp, " current op: %s\n", CodeName[*pc]);
- MaybeDumpScope(i.script()->lookupScope(pc), fp);
+ out.printf(" pc = %p\n", pc);
+ out.printf(" current op: %s\n", CodeName[*pc]);
+ MaybeDumpScope(i.script()->lookupScope(pc), out);
}
if (i.isFunctionFrame())
- MaybeDumpValue("this", i.thisArgument(cx), fp);
+ MaybeDumpValue("this", i.thisArgument(cx), out);
if (!i.isJSJit()) {
- fprintf(fp, " rval: ");
- dumpValue(i.interpFrame()->returnValue(), fp);
- fputc('\n', fp);
+ out.put(" rval: ");
+ dumpValue(i.interpFrame()->returnValue(), out);
+ out.putChar('\n');
}
- fprintf(fp, " flags:");
+ out.put(" flags:");
if (i.isConstructing())
- fprintf(fp, " constructing");
+ out.put(" constructing");
if (!i.isJSJit() && i.interpFrame()->isDebuggerEvalFrame())
- fprintf(fp, " debugger eval");
+ out.put(" debugger eval");
if (i.isEvalFrame())
- fprintf(fp, " eval");
- fputc('\n', fp);
-
- fprintf(fp, " envChain: (JSObject*) %p\n", (void*) i.environmentChain(cx));
-
- fputc('\n', fp);
+ out.put(" eval");
+ out.putChar('\n');
+
+ out.printf(" envChain: (JSObject*) %p\n", (void*) i.environmentChain(cx));
+
+ out.putChar('\n');
}
}
#endif /* DEBUG */
+namespace js {
+
+// We don't want jsfriendapi.h to depend on GenericPrinter,
+// so these functions are declared directly in the cpp.
+
+JS_FRIEND_API(void)
+DumpBacktrace(JSContext* cx, js::GenericPrinter& out);
+
+}
+
JS_FRIEND_API(void)
js::DumpBacktrace(JSContext* cx, FILE* fp)
{
+ Fprinter out(fp);
+ js::DumpBacktrace(cx, out);
+}
+
+JS_FRIEND_API(void)
+js::DumpBacktrace(JSContext* cx, js::GenericPrinter& out)
+{
Sprinter sprinter(cx, false);
if (!sprinter.init()) {
- fprintf(fp, "js::DumpBacktrace: OOM\n");
+ out.put("js::DumpBacktrace: OOM\n");
return;
}
size_t depth = 0;
for (AllFramesIter i(cx); !i.done(); ++i, ++depth) {
const char* filename;
unsigned line;
if (i.hasScript()) {
filename = JS_GetScriptFilename(i.script());
@@ -3715,17 +3749,17 @@ js::DumpBacktrace(JSContext* cx, FILE* f
if (i.hasScript()) {
sprinter.printf(" (%p @ %zu)\n",
i.script(), i.script()->pcToOffset(i.pc()));
} else {
sprinter.printf(" (%p)\n", i.pc());
}
}
- fprintf(fp, "%s", sprinter.string());
+ out.printf("%s", sprinter.string());
#ifdef XP_WIN32
if (IsDebuggerPresent())
OutputDebugStringA(sprinter.string());
#endif
}
JS_FRIEND_API(void)
js::DumpBacktrace(JSContext* cx)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -19,16 +19,17 @@
#include "mozilla/MemoryReporting.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/Conversions.h"
#include "js/GCAPI.h"
#include "js/GCVector.h"
#include "js/HeapAPI.h"
+#include "vm/Printer.h"
#include "vm/Shape.h"
#include "vm/String.h"
#include "vm/Xdr.h"
namespace JS {
struct ClassInfo;
} // namespace JS
@@ -578,17 +579,17 @@ class JSObject : public js::gc::Cell
template <class T>
const T& as() const {
MOZ_ASSERT(this->is<T>());
return *static_cast<const T*>(this);
}
#ifdef DEBUG
- void dump(FILE* fp) const;
+ void dump(js::GenericPrinter& fp) const;
void dump() const;
#endif
/* JIT Accessors */
static size_t offsetOfGroup() { return offsetof(JSObject, group_); }
// Maximum size in bytes of a JSObject.
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -88,16 +88,17 @@
#include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/Compression.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
#include "vm/Monitor.h"
#include "vm/MutexIDs.h"
+#include "vm/Printer.h"
#include "vm/Shape.h"
#include "vm/SharedArrayObject.h"
#include "vm/StringBuffer.h"
#include "vm/Time.h"
#include "vm/TypedArrayObject.h"
#include "vm/WrapperObject.h"
#include "wasm/WasmJS.h"
@@ -4304,18 +4305,19 @@ Parse(JSContext* cx, unsigned argc, Valu
nullptr);
if (!parser.checkOptions())
return false;
ParseNode* pn = parser.parse();
if (!pn)
return false;
#ifdef DEBUG
- DumpParseTree(pn);
- fputc('\n', stderr);
+ js::Fprinter out(stderr);
+ DumpParseTree(pn, out);
+ out.putChar('\n');
#endif
args.rval().setUndefined();
return true;
}
static bool
SyntaxParse(JSContext* cx, unsigned argc, Value* vp)
{
--- a/js/src/vm/Printer.h
+++ b/js/src/vm/Printer.h
@@ -33,20 +33,24 @@ class GenericPrinter
bool hadOOM_; // whether reportOutOfMemory() has been called.
GenericPrinter();
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();
@@ -141,17 +145,17 @@ class Fprinter final : public GenericPri
~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 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);|
};
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -39,16 +39,17 @@
#include "gc/Policy.h"
#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/CharacterEncoding.h"
#include "js/Date.h"
#include "vm/Compression.h"
#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
+#include "vm/Printer.h"
#include "vm/RegExpObject.h"
#include "vm/String.h"
#include "vm/StringBuffer.h"
#include "vm/TypedArrayObject.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
#include "jsfuninlines.h"
@@ -406,19 +407,20 @@ static bool
intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp)
{
#ifdef DEBUG
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() > 0) {
// try to dump the informative string
JSString* str = ToString<CanGC>(cx, args[0]);
if (str) {
- fprintf(stderr, "Self-hosted JavaScript assertion info: ");
- str->dumpCharsNoNewline();
- fputc('\n', stderr);
+ js::Fprinter out(stderr);
+ out.put("Self-hosted JavaScript assertion info: ");
+ str->dumpCharsNoNewline(out);
+ out.putChar('\n');
}
}
#endif
MOZ_ASSERT(false);
return false;
}
/**
@@ -426,20 +428,21 @@ intrinsic_AssertionFailed(JSContext* cx,
*/
static bool
intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef DEBUG
if (args.length() > 0) {
// try to dump the informative string
+ js::Fprinter out(stderr);
JSString* str = ToString<CanGC>(cx, args[0]);
if (str) {
- str->dumpCharsNoNewline();
- fputc('\n', stderr);
+ str->dumpCharsNoNewline(out);
+ out.putChar('\n');
} else {
cx->recoverFromOutOfMemory();
}
}
#endif
args.rval().setUndefined();
return true;
}
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1769,89 +1769,89 @@ KidsPointer::checkConsistency(Shape* aKi
MOZ_ASSERT(isHash());
KidsHash* hash = toHash();
KidsHash::Ptr ptr = hash->lookup(StackShape(aKid));
MOZ_ASSERT(*ptr == aKid);
}
}
void
-Shape::dump(FILE* fp) const
+Shape::dump(js::GenericPrinter& out) const
{
jsid propid = this->propid();
MOZ_ASSERT(!JSID_IS_VOID(propid));
if (JSID_IS_INT(propid)) {
- fprintf(fp, "[%ld]", (long) JSID_TO_INT(propid));
+ out.printf("[%ld]", (long) JSID_TO_INT(propid));
} else if (JSID_IS_ATOM(propid)) {
if (JSLinearString* str = JSID_TO_ATOM(propid))
- FileEscapedString(fp, str, '"');
+ EscapedStringPrinter(out, str, '"');
else
- fputs("<error>", fp);
+ out.put("<error>");
} else {
MOZ_ASSERT(JSID_IS_SYMBOL(propid));
- JSID_TO_SYMBOL(propid)->dump(fp);
+ JSID_TO_SYMBOL(propid)->dump(out);
}
- fprintf(fp, " g/s %p/%p slot %d attrs %x ",
- JS_FUNC_TO_DATA_PTR(void*, getter()),
- JS_FUNC_TO_DATA_PTR(void*, setter()),
- hasSlot() ? slot() : -1, attrs);
+ out.printf(" g/s %p/%p slot %d attrs %x ",
+ JS_FUNC_TO_DATA_PTR(void*, getter()),
+ JS_FUNC_TO_DATA_PTR(void*, setter()),
+ hasSlot() ? slot() : -1, attrs);
if (attrs) {
int first = 1;
- fputs("(", fp);
-#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(&(" " #display)[first], fp), first = 0
+ out.putChar('(');
+#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) out.put(&(" " #display)[first]), first = 0
DUMP_ATTR(ENUMERATE, enumerate);
DUMP_ATTR(READONLY, readonly);
DUMP_ATTR(PERMANENT, permanent);
DUMP_ATTR(GETTER, getter);
DUMP_ATTR(SETTER, setter);
DUMP_ATTR(SHARED, shared);
#undef DUMP_ATTR
- fputs(") ", fp);
+ out.putChar(')');
}
- fprintf(fp, "flags %x ", flags);
+ out.printf("flags %x ", flags);
if (flags) {
int first = 1;
- fputs("(", fp);
-#define DUMP_FLAG(name, display) if (flags & name) fputs(&(" " #display)[first], fp), first = 0
+ out.putChar('(');
+#define DUMP_FLAG(name, display) if (flags & name) out.put(&(" " #display)[first]), first = 0
DUMP_FLAG(IN_DICTIONARY, in_dictionary);
#undef DUMP_FLAG
- fputs(") ", fp);
+ out.putChar(')');
}
}
void
-Shape::dumpSubtree(int level, FILE* fp) const
+Shape::dumpSubtree(int level, js::GenericPrinter& out) const
{
if (!parent) {
MOZ_ASSERT(level == 0);
MOZ_ASSERT(JSID_IS_EMPTY(propid_));
- fprintf(fp, "class %s emptyShape\n", getObjectClass()->name);
+ out.printf("class %s emptyShape\n", getObjectClass()->name);
} else {
- fprintf(fp, "%*sid ", level, "");
- dump(fp);
+ out.printf("%*sid ", level, "");
+ dump(out);
}
if (!kids.isNull()) {
++level;
if (kids.isShape()) {
Shape* kid = kids.toShape();
MOZ_ASSERT(kid->parent == this);
- kid->dumpSubtree(level, fp);
+ kid->dumpSubtree(level, out);
} else {
const KidsHash& hash = *kids.toHash();
for (KidsHash::Range range = hash.all(); !range.empty(); range.popFront()) {
Shape* kid = range.front();
MOZ_ASSERT(kid->parent == this);
- kid->dumpSubtree(level, fp);
+ kid->dumpSubtree(level, out);
}
}
}
}
#endif
static bool
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -25,16 +25,17 @@
#include "gc/Heap.h"
#include "gc/Marking.h"
#include "gc/Rooting.h"
#include "js/HashTable.h"
#include "js/MemoryMetrics.h"
#include "js/RootingAPI.h"
#include "js/UbiNode.h"
#include "vm/ObjectGroup.h"
+#include "vm/Printer.h"
#include "vm/String.h"
#include "vm/Symbol.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4800)
#pragma warning(push)
#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
@@ -1135,18 +1136,18 @@ class Shape : public gc::TenuredCell
bool res = isBigEnoughForAShapeTableSlow();
if (res)
flags |= CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
flags |= HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE;
return res;
}
#ifdef DEBUG
- void dump(FILE* fp) const;
- void dumpSubtree(int level, FILE* fp) const;
+ void dump(js::GenericPrinter& out) const;
+ void dumpSubtree(int level, js::GenericPrinter& out) const;
#endif
void sweep();
void finalize(FreeOp* fop);
void removeChild(Shape* child);
static const JS::TraceKind TraceKind = JS::TraceKind::Shape;
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -100,136 +100,132 @@ JS::ubi::Concrete<JSString>::size(mozill
}
const char16_t JS::ubi::Concrete<JSString>::concreteTypeName[] = u"JSString";
#ifdef DEBUG
template <typename CharT>
/*static */ void
-JSString::dumpChars(const CharT* s, size_t n, FILE* fp)
+JSString::dumpChars(const CharT* s, size_t n, js::GenericPrinter& out)
{
if (n == SIZE_MAX) {
n = 0;
while (s[n])
n++;
}
- fputc('"', fp);
+ out.put("\"");
for (size_t i = 0; i < n; i++) {
char16_t c = s[i];
if (c == '\n')
- fprintf(fp, "\\n");
+ out.put("\\n");
else if (c == '\t')
- fprintf(fp, "\\t");
+ out.put("\\t");
else if (c >= 32 && c < 127)
- fputc(s[i], fp);
+ out.putChar((char)s[i]);
else if (c <= 255)
- fprintf(fp, "\\x%02x", unsigned(c));
+ out.printf("\\x%02x", unsigned(c));
else
- fprintf(fp, "\\u%04x", unsigned(c));
+ out.printf("\\u%04x", unsigned(c));
}
- fputc('"', fp);
+ out.putChar('"');
}
template void
-JSString::dumpChars(const Latin1Char* s, size_t n, FILE* fp);
+JSString::dumpChars(const Latin1Char* s, size_t n, js::GenericPrinter& out);
template void
-JSString::dumpChars(const char16_t* s, size_t n, FILE* fp);
+JSString::dumpChars(const char16_t* s, size_t n, js::GenericPrinter& out);
void
-JSString::dumpCharsNoNewline(FILE* fp)
+JSString::dumpCharsNoNewline(js::GenericPrinter& out)
{
if (JSLinearString* linear = ensureLinear(nullptr)) {
AutoCheckCannotGC nogc;
if (hasLatin1Chars())
- dumpChars(linear->latin1Chars(nogc), length(), fp);
+ dumpChars(linear->latin1Chars(nogc), length(), out);
else
- dumpChars(linear->twoByteChars(nogc), length(), fp);
+ dumpChars(linear->twoByteChars(nogc), length(), out);
} else {
- fprintf(fp, "(oom in JSString::dumpCharsNoNewline)");
+ out.put("(oom in JSString::dumpCharsNoNewline)");
}
}
void
-JSString::dump(FILE* fp)
+JSString::dump()
+{
+ js::Fprinter out(stderr);
+ dump(out);
+}
+
+void
+JSString::dump(js::GenericPrinter& out)
{
if (JSLinearString* linear = ensureLinear(nullptr)) {
AutoCheckCannotGC nogc;
if (hasLatin1Chars()) {
const Latin1Char* chars = linear->latin1Chars(nogc);
- fprintf(fp, "JSString* (%p) = Latin1Char * (%p) = ", (void*) this,
+ out.printf("JSString* (%p) = Latin1Char * (%p) = ", (void*) this,
(void*) chars);
- dumpChars(chars, length(), fp);
+ dumpChars(chars, length(), out);
} else {
const char16_t* chars = linear->twoByteChars(nogc);
- fprintf(fp, "JSString* (%p) = char16_t * (%p) = ", (void*) this,
+ out.printf("JSString* (%p) = char16_t * (%p) = ", (void*) this,
(void*) chars);
- dumpChars(chars, length(), fp);
+ dumpChars(chars, length(), out);
}
} else {
- fprintf(fp, "(oom in JSString::dump)");
+ out.put("(oom in JSString::dump)");
}
- fputc('\n', fp);
+ out.putChar('\n');
}
+
void
-JSString::dumpCharsNoNewline()
-{
- dumpCharsNoNewline(stderr);
-}
-
-void
-JSString::dump()
+JSString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dump(stderr);
-}
-
-void
-JSString::dumpRepresentation(FILE* fp, int indent) const
-{
- if (isRope()) asRope() .dumpRepresentation(fp, indent);
- else if (isDependent()) asDependent() .dumpRepresentation(fp, indent);
- else if (isExternal()) asExternal() .dumpRepresentation(fp, indent);
- else if (isExtensible()) asExtensible() .dumpRepresentation(fp, indent);
- else if (isInline()) asInline() .dumpRepresentation(fp, indent);
- else if (isFlat()) asFlat() .dumpRepresentation(fp, indent);
+ if (isRope()) asRope() .dumpRepresentation(out, indent);
+ else if (isDependent()) asDependent() .dumpRepresentation(out, indent);
+ else if (isExternal()) asExternal() .dumpRepresentation(out, indent);
+ else if (isExtensible()) asExtensible() .dumpRepresentation(out, indent);
+ else if (isInline()) asInline() .dumpRepresentation(out, indent);
+ else if (isFlat()) asFlat() .dumpRepresentation(out, indent);
else
MOZ_CRASH("Unexpected JSString representation");
}
void
-JSString::dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const
+JSString::dumpRepresentationHeader(js::GenericPrinter& out, int indent, const char* subclass) const
{
uint32_t flags = d.u1.flags;
// Print the string's address as an actual C++ expression, to facilitate
// copy-and-paste into a debugger.
- fprintf(fp, "((%s*) %p) length: %zu flags: 0x%x", subclass, this, length(), flags);
- if (flags & FLAT_BIT) fputs(" FLAT", fp);
- if (flags & HAS_BASE_BIT) fputs(" HAS_BASE", fp);
- if (flags & INLINE_CHARS_BIT) fputs(" INLINE_CHARS", fp);
- if (flags & ATOM_BIT) fputs(" ATOM", fp);
- if (isPermanentAtom()) fputs(" PERMANENT", fp);
- if (flags & LATIN1_CHARS_BIT) fputs(" LATIN1", fp);
- if (flags & INDEX_VALUE_BIT) fprintf(fp, " INDEX_VALUE(%u)", getIndexValue());
- fputc('\n', fp);
+ out.printf("((%s*) %p) length: %zu flags: 0x%x", subclass, this, length(), flags);
+ if (flags & FLAT_BIT) out.put(" FLAT");
+ if (flags & HAS_BASE_BIT) out.put(" HAS_BASE");
+ if (flags & INLINE_CHARS_BIT) out.put(" INLINE_CHARS");
+ if (flags & ATOM_BIT) out.put(" ATOM");
+ if (isPermanentAtom()) out.put(" PERMANENT");
+ if (flags & LATIN1_CHARS_BIT) out.put(" LATIN1");
+ if (flags & INDEX_VALUE_BIT) out.put(" INDEX_VALUE(%u)", getIndexValue());
+ out.putChar('\n');
}
void
-JSLinearString::dumpRepresentationChars(FILE* fp, int indent) const
+JSLinearString::dumpRepresentationChars(js::GenericPrinter& out, int indent) const
{
if (hasLatin1Chars()) {
- fprintf(fp, "%*schars: ((Latin1Char*) %p) ", indent, "", rawLatin1Chars());
- dumpChars(rawLatin1Chars(), length());
+ out.printf("%*schars: ((Latin1Char*) %p) ", indent, "", rawLatin1Chars());
+ dumpChars(rawLatin1Chars(), length(), out);
} else {
- fprintf(fp, "%*schars: ((char16_t*) %p) ", indent, "", rawTwoByteChars());
- dumpChars(rawTwoByteChars(), length());
+ out.printf("%*schars: ((char16_t*) %p) ", indent, "", rawTwoByteChars());
+ dumpChars(rawTwoByteChars(), length(), out);
}
- fputc('\n', fp);
+ out.putChar('\n');
}
bool
JSString::equals(const char* s)
{
JSLinearString* linear = ensureLinear(nullptr);
if (!linear) {
fprintf(stderr, "OOM in JSString::equals!\n");
@@ -332,26 +328,26 @@ JSRope::copyCharsInternal(JSContext* cx,
if (nullTerminate)
out[n] = 0;
return true;
}
#ifdef DEBUG
void
-JSRope::dumpRepresentation(FILE* fp, int indent) const
+JSRope::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent, "JSRope");
+ dumpRepresentationHeader(out, indent, "JSRope");
indent += 2;
- fprintf(fp, "%*sleft: ", indent, "");
- leftChild()->dumpRepresentation(fp, indent);
+ out.printf("%*sleft: ", indent, "");
+ leftChild()->dumpRepresentation(out, indent);
- fprintf(fp, "%*sright: ", indent, "");
- rightChild()->dumpRepresentation(fp, indent);
+ out.printf("%*sright: ", indent, "");
+ rightChild()->dumpRepresentation(out, indent);
}
#endif
namespace js {
template <>
void
CopyChars(char16_t* dest, const JSLinearString& str)
@@ -710,26 +706,26 @@ JSDependentString::undepend(JSContext* c
MOZ_ASSERT(JSString::isDependent());
return hasLatin1Chars()
? undependInternal<Latin1Char>(cx)
: undependInternal<char16_t>(cx);
}
#ifdef DEBUG
void
-JSDependentString::dumpRepresentation(FILE* fp, int indent) const
+JSDependentString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent, "JSDependentString");
+ dumpRepresentationHeader(out, indent, "JSDependentString");
indent += 2;
if (mozilla::Maybe<size_t> offset = baseOffset())
- fprintf(fp, "%*soffset: %zu\n", indent, "", *offset);
+ out.printf("%*soffset: %zu\n", indent, "", *offset);
- fprintf(fp, "%*sbase: ", indent, "");
- base()->dumpRepresentation(fp, indent);
+ out.printf("%*sbase: ", indent, "");
+ base()->dumpRepresentation(out, indent);
}
#endif
template <typename CharT>
/* static */ bool
JSFlatString::isIndexSlow(const CharT* s, size_t length, uint32_t* indexp)
{
CharT ch = *s;
@@ -1103,36 +1099,37 @@ JSExternalString::ensureFlat(JSContext*
setNonInlineChars<char16_t>(s);
d.u1.flags = FLAT_BIT;
return &this->asFlat();
}
#ifdef DEBUG
void
-JSAtom::dump(FILE* fp)
+JSAtom::dump(js::GenericPrinter& out)
{
- fprintf(fp, "JSAtom* (%p) = ", (void*) this);
- this->JSString::dump(fp);
+ out.printf("JSAtom* (%p) = ", (void*) this);
+ this->JSString::dump(out);
}
void
JSAtom::dump()
{
- dump(stderr);
+ Fprinter out(stderr);
+ dump(out);
}
void
-JSExternalString::dumpRepresentation(FILE* fp, int indent) const
+JSExternalString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent, "JSExternalString");
+ dumpRepresentationHeader(out, indent, "JSExternalString");
indent += 2;
- fprintf(fp, "%*sfinalizer: ((JSStringFinalizer*) %p)\n", indent, "", externalFinalizer());
- dumpRepresentationChars(fp, indent);
+ out.printf("%*sfinalizer: ((JSStringFinalizer*) %p)\n", indent, "", externalFinalizer());
+ dumpRepresentationChars(out, indent);
}
#endif /* DEBUG */
JSLinearString*
js::NewDependentString(JSContext* cx, JSString* baseArg, size_t start, size_t length)
{
if (length == 0)
return cx->emptyString();
@@ -1484,42 +1481,42 @@ NewMaybeExternalString(JSContext* cx, co
cache.put(str);
return str;
}
} /* namespace js */
#ifdef DEBUG
void
-JSExtensibleString::dumpRepresentation(FILE* fp, int indent) const
+JSExtensibleString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent, "JSExtensibleString");
+ dumpRepresentationHeader(out, indent, "JSExtensibleString");
indent += 2;
- fprintf(fp, "%*scapacity: %zu\n", indent, "", capacity());
- dumpRepresentationChars(fp, indent);
+ out.printf("%*scapacity: %zu\n", indent, "", capacity());
+ dumpRepresentationChars(out, indent);
}
void
-JSInlineString::dumpRepresentation(FILE* fp, int indent) const
+JSInlineString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent,
+ dumpRepresentationHeader(out, indent,
isFatInline() ? "JSFatInlineString" : "JSThinInlineString");
indent += 2;
- dumpRepresentationChars(fp, indent);
+ dumpRepresentationChars(out, indent);
}
void
-JSFlatString::dumpRepresentation(FILE* fp, int indent) const
+JSFlatString::dumpRepresentation(js::GenericPrinter& out, int indent) const
{
- dumpRepresentationHeader(fp, indent, "JSFlatString");
+ dumpRepresentationHeader(out, indent, "JSFlatString");
indent += 2;
- dumpRepresentationChars(fp, indent);
+ dumpRepresentationChars(out, indent);
}
#endif
static void
FinalizeRepresentativeExternalString(const JSStringFinalizer* fin, char16_t* chars);
static const JSStringFinalizer RepresentativeExternalStringFinalizer =
{ FinalizeRepresentativeExternalString };
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -18,16 +18,18 @@
#include "gc/Barrier.h"
#include "gc/Heap.h"
#include "gc/Marking.h"
#include "gc/Rooting.h"
#include "js/CharacterEncoding.h"
#include "js/GCAPI.h"
#include "js/RootingAPI.h"
+#include "vm/Printer.h"
+
class JSDependentString;
class JSExtensibleString;
class JSExternalString;
class JSInlineString;
class JSRope;
namespace js {
@@ -521,25 +523,24 @@ class JSString : public js::gc::TenuredC
offsetof(JSString, d.s.u2.nonInlineCharsLatin1),
"nonInlineCharsTwoByte and nonInlineCharsLatin1 must have same offset");
return offsetof(JSString, d.s.u2.nonInlineCharsTwoByte);
}
static const JS::TraceKind TraceKind = JS::TraceKind::String;
#ifdef DEBUG
- void dump(FILE* fp);
- void dumpCharsNoNewline(FILE* fp);
- void dump();
- void dumpCharsNoNewline();
- void dumpRepresentation(FILE* fp, int indent) const;
- void dumpRepresentationHeader(FILE* fp, int indent, const char* subclass) const;
+ void dump(); // Debugger-friendly stderr dump.
+ void dump(js::GenericPrinter& out);
+ void dumpCharsNoNewline(js::GenericPrinter& out);
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
+ void dumpRepresentationHeader(js::GenericPrinter& out, int indent, const char* subclass) const;
template <typename CharT>
- static void dumpChars(const CharT* s, size_t len, FILE* fp=stderr);
+ static void dumpChars(const CharT* s, size_t len, js::GenericPrinter& out);
bool equals(const char* s);
#endif
void traceChildren(JSTracer* trc);
static MOZ_ALWAYS_INLINE void readBarrier(JSString* thing) {
if (thing->isPermanentAtom())
@@ -613,17 +614,17 @@ class JSRope : public JSString
static size_t offsetOfLeft() {
return offsetof(JSRope, d.s.u2.left);
}
static size_t offsetOfRight() {
return offsetof(JSRope, d.s.u3.right);
}
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSRope) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSLinearString : public JSString
{
@@ -696,17 +697,17 @@ class JSLinearString : public JSString
char16_t latin1OrTwoByteChar(size_t index) const {
MOZ_ASSERT(JSString::isLinear());
MOZ_ASSERT(index < length());
JS::AutoCheckCannotGC nogc;
return hasLatin1Chars() ? latin1Chars(nogc)[index] : twoByteChars(nogc)[index];
}
#ifdef DEBUG
- void dumpRepresentationChars(FILE* fp, int indent) const;
+ void dumpRepresentationChars(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSLinearString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSDependentString : public JSLinearString
{
@@ -742,17 +743,17 @@ class JSDependentString : public JSLinea
static inline JSLinearString* new_(JSContext* cx, JSLinearString* base,
size_t start, size_t length);
inline static size_t offsetOfBase() {
return offsetof(JSDependentString, d.s.u3.base);
}
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSDependentString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSFlatString : public JSLinearString
{
@@ -827,17 +828,17 @@ class JSFlatString : public JSLinearStri
* operation changes the string to the JSAtom type, in place.
*/
MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoAtom(js::HashNumber hash);
MOZ_ALWAYS_INLINE JSAtom* morphAtomizedStringIntoPermanentAtom(js::HashNumber hash);
inline void finalize(js::FreeOp* fop);
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSFlatString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSExtensibleString : public JSFlatString
{
@@ -848,17 +849,17 @@ class JSExtensibleString : public JSFlat
public:
MOZ_ALWAYS_INLINE
size_t capacity() const {
MOZ_ASSERT(JSString::isExtensible());
return d.s.u3.capacity;
}
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSExtensibleString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSInlineString : public JSFlatString
{
@@ -880,17 +881,17 @@ class JSInlineString : public JSFlatStri
template<typename CharT>
static bool lengthFits(size_t length);
static size_t offsetOfInlineStorage() {
return offsetof(JSInlineString, d.inlineStorageTwoByte);
}
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSInlineString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
/*
* On 32-bit platforms, JSThinInlineString can store 7 Latin1 characters or 3
@@ -994,17 +995,17 @@ class JSExternalString : public JSLinear
/* Only called by the GC for strings with the AllocKind::EXTERNAL_STRING kind. */
inline void finalize(js::FreeOp* fop);
JSFlatString* ensureFlat(JSContext* cx);
#ifdef DEBUG
- void dumpRepresentation(FILE* fp, int indent) const;
+ void dumpRepresentation(js::GenericPrinter& out, int indent) const;
#endif
};
static_assert(sizeof(JSExternalString) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
class JSUndependedString : public JSFlatString
{
@@ -1040,17 +1041,17 @@ class JSAtom : public JSFlatString
MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
d.u1.flags |= PERMANENT_ATOM_MASK;
}
inline js::HashNumber hash() const;
inline void initHash(js::HashNumber hash);
#ifdef DEBUG
- void dump(FILE* fp);
+ void dump(js::GenericPrinter& out);
void dump();
#endif
};
static_assert(sizeof(JSAtom) == sizeof(JSString),
"string subclasses must be binary-compatible with JSString");
namespace js {
--- a/js/src/vm/Symbol.cpp
+++ b/js/src/vm/Symbol.cpp
@@ -92,35 +92,42 @@ Symbol::for_(JSContext* cx, HandleString
}
}
cx->markAtom(sym);
return sym;
}
#ifdef DEBUG
void
-Symbol::dump(FILE* fp)
+Symbol::dump()
+{
+ js::Fprinter out(stderr);
+ dump(out);
+}
+
+void
+Symbol::dump(js::GenericPrinter& out)
{
if (isWellKnownSymbol()) {
// All the well-known symbol names are ASCII.
- description_->dumpCharsNoNewline(fp);
+ description_->dumpCharsNoNewline(out);
} else if (code_ == SymbolCode::InSymbolRegistry || code_ == SymbolCode::UniqueSymbol) {
- fputs(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" : "Symbol(", fp);
+ out.printf(code_ == SymbolCode::InSymbolRegistry ? "Symbol.for(" : "Symbol(");
if (description_)
- description_->dumpCharsNoNewline(fp);
+ description_->dumpCharsNoNewline(out);
else
- fputs("undefined", fp);
+ out.printf("undefined");
- fputc(')', fp);
+ out.putChar(')');
if (code_ == SymbolCode::UniqueSymbol)
- fprintf(fp, "@%p", (void*) this);
+ out.printf("@%p", (void*) this);
} else {
- fprintf(fp, "<Invalid Symbol code=%u>", unsigned(code_));
+ out.printf("<Invalid Symbol code=%u>", unsigned(code_));
}
}
#endif // DEBUG
bool
js::SymbolDescriptiveString(JSContext* cx, Symbol* sym, MutableHandleValue result)
{
// steps 2-5
--- a/js/src/vm/Symbol.h
+++ b/js/src/vm/Symbol.h
@@ -15,16 +15,17 @@
#include "jsapi.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/GCHashTable.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
+#include "vm/Printer.h"
#include "vm/String.h"
namespace js {
class AutoLockForExclusiveAccess;
} // namespace js
namespace JS {
@@ -89,17 +90,18 @@ class Symbol : public js::gc::TenuredCel
thing->asTenured().writeBarrierPre(thing);
}
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(this);
}
#ifdef DEBUG
- void dump(FILE* fp = stderr);
+ void dump(); // Debugger-friendly stderr dump.
+ void dump(js::GenericPrinter& out);
#endif
};
} /* namespace JS */
namespace js {
/* Hash policy used by the SymbolRegistry. */
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -26,16 +26,17 @@
#include "jit/CompileInfo.h"
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "jit/JitCompartment.h"
#include "jit/OptimizationTracking.h"
#include "js/MemoryMetrics.h"
#include "vm/HelperThreads.h"
#include "vm/Opcodes.h"
+#include "vm/Printer.h"
#include "vm/Shape.h"
#include "vm/Time.h"
#include "vm/UnboxedObject.h"
#include "jsatominlines.h"
#include "jsscriptinlines.h"
#include "vm/NativeObject-inl.h"
@@ -4629,29 +4630,30 @@ void
TypeScript::printTypes(JSContext* cx, HandleScript script) const
{
MOZ_ASSERT(script->types() == this);
if (!script->hasBaselineScript())
return;
AutoEnterAnalysis enter(nullptr, script->zone());
+ Fprinter out(stderr);
if (script->functionNonDelazifying())
fprintf(stderr, "Function");
else if (script->isForEval())
fprintf(stderr, "Eval");
else
fprintf(stderr, "Main");
fprintf(stderr, " %#" PRIxPTR " %s:%zu ",
uintptr_t(script.get()), script->filename(), script->lineno());
if (script->functionNonDelazifying()) {
if (JSAtom* name = script->functionNonDelazifying()->explicitName())
- name->dumpCharsNoNewline();
+ name->dumpCharsNoNewline(out);
}
fprintf(stderr, "\n this:");
TypeScript::ThisTypes(script)->print();
for (unsigned i = 0;
script->functionNonDelazifying() && i < script->functionNonDelazifying()->nargs();
i++)