Bug 1413997 - Improve readability of js::DumpObject() output r=jandem
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 03 Nov 2017 10:25:25 +0000
changeset 443300 101466a6bd46d25c6e079e9e1e07b342afcc0735
parent 443299 c5561749c1c64793c31699d46bbf12cc0c69815c
child 443301 79def5ebdec25eb87e18fc1694bb44ed2ae8886d
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1413997
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1413997 - Improve readability of js::DumpObject() output r=jandem
js/src/jsobj.cpp
js/src/vm/String.cpp
js/src/vm/String.h
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3406,17 +3406,17 @@ dumpValue(const Value& v, js::GenericPri
         out.put("null");
     else if (v.isUndefined())
         out.put("undefined");
     else if (v.isInt32())
         out.printf("%d", v.toInt32());
     else if (v.isDouble())
         out.printf("%g", v.toDouble());
     else if (v.isString())
-        v.toString()->dump(out);
+        v.toString()->dumpNoNewline(out);
     else if (v.isSymbol())
         v.toSymbol()->dump(out);
     else if (v.isObject() && v.toObject().is<JSFunction>()) {
         JSFunction* fun = &v.toObject().as<JSFunction>();
         if (fun->displayAtom()) {
             out.put("<function ");
             EscapedStringPrinter(out, fun->displayAtom(), 0);
         } else {
@@ -3487,47 +3487,51 @@ js::DumpId(jsid id, js::GenericPrinter& 
     dumpValue(IdToValue(id), out);
     out.putChar('\n');
 }
 
 static void
 DumpProperty(const NativeObject* obj, Shape& shape, js::GenericPrinter& out)
 {
     jsid id = shape.propid();
+    if (JSID_IS_ATOM(id))
+        JSID_TO_ATOM(id)->dumpCharsNoNewline(out);
+    else if (JSID_IS_INT(id))
+       out.printf("%d", JSID_TO_INT(id));
+    else if (JSID_IS_SYMBOL(id))
+        JSID_TO_SYMBOL(id)->dump(out);
+    else
+        out.printf("id %p", reinterpret_cast<void*>(JSID_BITS(id)));
+
+    if (shape.isDataProperty()) {
+        out.printf(": ");
+        dumpValue(obj->getSlot(shape.maybeSlot()), out);
+    }
+
+    out.printf(" (shape %p", (void*) &shape);
+
     uint8_t attrs = shape.attributes();
-
-    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_ENUMERATE) out.put(" enumerate");
+    if (attrs & JSPROP_READONLY) out.put(" readonly");
+    if (attrs & JSPROP_PERMANENT) out.put(" permanent");
 
     if (shape.hasGetterValue())
-        out.printf("getterValue=%p ", (void*) shape.getterObject());
+        out.printf(" getterValue %p", shape.getterObject());
     else if (!shape.hasDefaultGetter())
-        out.printf("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())
-        out.printf("setterValue=%p ", (void*) shape.setterObject());
+        out.printf(" setterValue %p", shape.setterObject());
     else if (!shape.hasDefaultSetter())
-        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), out);
-    else
-        out.printf("unknown jsid %p", (void*) JSID_BITS(id));
-
-    uint32_t slot = shape.isDataProperty() ? shape.maybeSlot() : SHAPE_INVALID_SLOT;
-    out.printf(": slot %d", slot);
-    if (shape.isDataProperty()) {
-        out.put(" = ");
-        dumpValue(obj->getSlot(slot), out);
-    } else if (slot != SHAPE_INVALID_SLOT) {
-        out.printf(" (INVALID!)");
-    }
-    out.putChar('\n');
+        out.printf(" setterOp %p", JS_FUNC_TO_DATA_PTR(void*, shape.setterOp()));
+
+    if (shape.isDataProperty())
+        out.printf(" slot %d", shape.maybeSlot());
+
+    out.printf(")\n");
 }
 
 bool
 JSObject::uninlinedIsProxy() const
 {
     return is<ProxyObject>();
 }
 
@@ -3537,111 +3541,105 @@ JSObject::uninlinedNonProxyIsExtensible(
     return nonProxyIsExtensible();
 }
 
 void
 JSObject::dump(js::GenericPrinter& out) const
 {
     const JSObject* obj = this;
     JSObject* globalObj = &global();
-    out.printf("object %p from global %p [%s]\n", (void*) obj,
-            (void*) globalObj, globalObj->getClass()->name);
+    out.printf("object %p\n", obj);
+    out.printf("  global %p [%s]\n", globalObj, globalObj->getClass()->name);
+
     const Class* clasp = obj->getClass();
-    out.printf("class %p %s\n", (const void*)clasp, clasp->name);
+    out.printf("  class %p %s\n", clasp, clasp->name);
 
     if (obj->hasLazyGroup()) {
-        out.put("lazy group\n");
+        out.put("  lazy group\n");
     } else {
         const ObjectGroup* group = obj->group();
-        out.printf("group %p\n", (const void*)group);
+        out.printf("  group %p\n", group);
     }
 
-    out.put("flags:");
+    out.put("  flags:");
     if (obj->isDelegate()) out.put(" delegate");
     if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) out.put(" not_extensible");
     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->isIteratedSingleton()) out.put(" iterated_singleton");
     if (obj->isNewGroupUnknown()) out.put(" new_type_unknown");
     if (obj->hasUncacheableProto()) out.put(" has_uncacheable_proto");
     if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable())
         out.put(" immutable_prototype");
 
-    if (obj->isNative()) {
-        const NativeObject* nobj = &obj->as<NativeObject>();
+    const NativeObject* nobj = obj->isNative() ? &obj->as<NativeObject>() : nullptr;
+    if (nobj) {
         if (nobj->inDictionaryMode())
             out.put(" inDictionaryMode");
         if (nobj->hasShapeTable())
             out.put(" hasShapeTable");
         if (nobj->hadElementsAccess())
             out.put(" had_elements_access");
         if (nobj->isIndexed())
             out.put(" indexed");
         if (nobj->wasNewScriptCleared())
             out.put(" new_script_cleared");
+    } else {
+        out.put(" not_native\n");
     }
     out.putChar('\n');
 
-    if (obj->isNative()) {
-        const NativeObject* nobj = &obj->as<NativeObject>();
-        uint32_t slots = nobj->getDenseInitializedLength();
-        if (slots) {
-            out.put("elements\n");
-            for (uint32_t i = 0; i < slots; i++) {
-                out.printf(" %3d: ", i);
-                dumpValue(nobj->getDenseElement(i), out);
-                out.putChar('\n');
-                out.flush();
-            }
-        }
-    }
-
-    out.put("proto ");
+    out.put("  proto ");
     TaggedProto proto = obj->taggedProto();
     if (proto.isDynamic())
         out.put("<dynamic>");
     else
         dumpValue(ObjectOrNullValue(proto.toObjectOrNull()), out);
     out.putChar('\n');
 
-    if (clasp->flags & JSCLASS_HAS_PRIVATE)
-        out.printf("private %p\n", obj->as<NativeObject>().getPrivate());
-
-    if (!obj->isNative())
-        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)
-        out.printf(obj->isNative() ? "reserved slots:\n" : "slots:\n");
-    for (uint32_t i = 0; i < stop; i++) {
-        out.printf(" %3d ", i);
-        if (i < reservedEnd)
-            out.printf("(reserved) ");
-        out.put("= ");
-        dumpValue(obj->as<NativeObject>().getSlot(i), out);
-        out.putChar('\n');
-    }
-
-    if (obj->isNative()) {
-        out.put("properties:\n");
+    if (nobj) {
+        if (clasp->flags & JSCLASS_HAS_PRIVATE)
+            out.printf("  private %p\n", nobj->getPrivate());
+
+        uint32_t reserved = JSCLASS_RESERVED_SLOTS(clasp);
+        if (reserved) {
+            out.printf("  reserved slots:\n");
+            for (uint32_t i = 0; i < reserved; i++) {
+                out.printf("    %3d ", i);
+                out.put(": ");
+                dumpValue(nobj->getSlot(i), out);
+                out.putChar('\n');
+            }
+        }
+
+        out.put("  properties:\n");
         Vector<Shape*, 8, SystemAllocPolicy> props;
-        for (Shape::Range<NoGC> r(obj->as<NativeObject>().lastProperty()); !r.empty(); r.popFront()) {
+        for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
             if (!props.append(&r.front())) {
                 out.printf("(OOM while appending properties)\n");
                 break;
             }
         }
-        for (size_t i = props.length(); i-- != 0;)
-            DumpProperty(&obj->as<NativeObject>(), *props[i], out);
+        for (size_t i = props.length(); i-- != 0;) {
+            out.printf("    ");
+            DumpProperty(nobj, *props[i], out);
+        }
+
+        uint32_t slots = nobj->getDenseInitializedLength();
+        if (slots) {
+            out.put("  elements:\n");
+            for (uint32_t i = 0; i < slots; i++) {
+                out.printf("    %3d: ", i);
+                dumpValue(nobj->getDenseElement(i), out);
+                out.putChar('\n');
+            }
+        }
     }
-    out.putChar('\n');
 }
 
 // For debuggers.
 void
 JSObject::dump() const
 {
     Fprinter out(stderr);
     dump(out);
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -155,33 +155,39 @@ JSString::dump()
 {
     js::Fprinter out(stderr);
     dump(out);
 }
 
 void
 JSString::dump(js::GenericPrinter& out)
 {
+    dumpNoNewline(out);
+    out.putChar('\n');
+}
+
+void
+JSString::dumpNoNewline(js::GenericPrinter& out)
+{
     if (JSLinearString* linear = ensureLinear(nullptr)) {
         AutoCheckCannotGC nogc;
         if (hasLatin1Chars()) {
             const Latin1Char* chars = linear->latin1Chars(nogc);
             out.printf("JSString* (%p) = Latin1Char * (%p) = ", (void*) this,
                     (void*) chars);
             dumpChars(chars, length(), out);
         } else {
             const char16_t* chars = linear->twoByteChars(nogc);
             out.printf("JSString* (%p) = char16_t * (%p) = ", (void*) this,
                     (void*) chars);
             dumpChars(chars, length(), out);
         }
     } else {
         out.put("(oom in JSString::dump)");
     }
-    out.putChar('\n');
 }
 
 
 void
 JSString::dumpRepresentation(js::GenericPrinter& out, int indent) const
 {
     if      (isRope())          asRope()        .dumpRepresentation(out, indent);
     else if (isDependent())     asDependent()   .dumpRepresentation(out, indent);
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -524,16 +524,17 @@ class JSString : public js::gc::TenuredC
         return offsetof(JSString, d.s.u2.nonInlineCharsTwoByte);
     }
 
     static const JS::TraceKind TraceKind = JS::TraceKind::String;
 
 #ifdef DEBUG
     void dump(); // Debugger-friendly stderr dump.
     void dump(js::GenericPrinter& out);
+    void dumpNoNewline(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, js::GenericPrinter& out);
 
     bool equals(const char* s);