[INFER] Colorize spew for constraints and typesets, bug 664583. r=bhackett
authorShu-yu Guo <shu@rfrn.org>
Wed, 15 Jun 2011 19:22:27 -0700
changeset 75166 61cbf09e7fa4fbff86136f6e4f2fd633fee43b3e
parent 75165 2993dfa0ce4d40f0faf22dca70f96d22c51b34a2
child 75167 9ff00d53b5a53e17c529aebb81125c0425f26015
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersbhackett
bugs664583
milestone7.0a1
[INFER] Colorize spew for constraints and typesets, bug 664583. r=bhackett
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -152,19 +152,52 @@ static bool InferSpewActive(SpewChannel 
         if (strstr(env, "full")) {
             for (unsigned i = 0; i < SPEW_COUNT; i++)
                 active[i] = true;
         }
     }
     return active[channel];
 }
 
+static bool InferSpewColorable()
+{
+    /* Only spew colors on xterm-color to not screw up emacs. */
+    const char *env = getenv("TERM");
+    if (!env)
+        return false;
+    return strcmp(env, "xterm-color") == 0;
+}
+
 #ifdef DEBUG
 
 const char *
+types::InferSpewColor(TypeConstraint *constraint)
+{
+    /* Type constraints are printed out using background colors. */
+    static const char *colors[] = { "\x1b[31m", "\x1b[32m", "\x1b[33m",
+                                    "\x1b[34m", "\x1b[35m", "\x1b[36m",
+                                    "\x1b[37m" };
+    if (!InferSpewColorable())
+        return "";
+    return colors[DefaultHasher<TypeConstraint *>::hash(constraint) % 7];
+}
+
+const char *
+types::InferSpewColor(TypeSet *types)
+{
+    /* Type sets are printed out using bold colors. */
+    static const char *colors[] = { "\x1b[1;31m", "\x1b[1;32m", "\x1b[1;33m",
+                                    "\x1b[1;34m", "\x1b[1;35m", "\x1b[1;36m",
+                                    "\x1b[1;37m" };
+    if (!InferSpewColorable())
+        return "";
+    return colors[DefaultHasher<TypeSet *>::hash(types) % 7];
+}
+
+const char *
 types::TypeString(jstype type)
 {
     switch (type) {
       case TYPE_UNDEFINED:
         return "void";
       case TYPE_NULL:
         return "null";
       case TYPE_BOOLEAN:
@@ -301,17 +334,19 @@ TypeSet::make(JSContext *cx, const char 
     JS_ASSERT(cx->compartment->activeInference);
 
     TypeSet *res = ArenaNew<TypeSet>(cx->compartment->pool);
     if (!res) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
     }
 
-    InferSpew(ISpewOps, "typeSet: T%p intermediate %s", res, name);
+    InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
+              InferSpewColor(res), res, InferSpewColorReset(),
+              name);
     res->setIntermediate();
 
     return res;
 }
 
 void
 TypeSet::addTypeSet(JSContext *cx, ClonedTypeSet *types)
 {
@@ -342,18 +377,20 @@ TypeSet::add(JSContext *cx, TypeConstrai
         return;
     }
 
     JS_ASSERT_IF(!constraint->condensed() && !constraint->persistentObject(),
                  constraint->script->compartment == cx->compartment);
     JS_ASSERT_IF(!constraint->condensed(), cx->compartment->activeInference);
     JS_ASSERT_IF(intermediate(), !constraint->persistentObject() && !constraint->condensed());
 
-    InferSpew(ISpewOps, "addConstraint: T%p C%p %s",
-              this, constraint, constraint->kind());
+    InferSpew(ISpewOps, "addConstraint: %sT%p%s %sC%p%s %s",
+              InferSpewColor(this), this, InferSpewColorReset(),
+              InferSpewColor(constraint), constraint, InferSpewColorReset(),
+              constraint->kind());
 
     JS_ASSERT(constraint->next == NULL);
     constraint->next = constraintList;
     constraintList = constraint;
 
     if (!callExisting)
         return;
 
@@ -2208,18 +2245,20 @@ ScriptAnalysis::addTypeBarrier(JSContext
     /* Ignore duplicate barriers. */
     TypeBarrier *barrier = code.typeBarriers;
     while (barrier) {
         if (barrier->target == target && barrier->type == type)
             return;
         barrier = barrier->next;
     }
 
-    InferSpew(ISpewOps, "typeBarrier: #%u:%05u: T%p %s",
-              script->id(), pc - script->code, target, TypeString(type));
+    InferSpew(ISpewOps, "typeBarrier: #%u:%05u: %sT%p%s %s",
+              script->id(), pc - script->code,
+              InferSpewColor(target), target, InferSpewColorReset(),
+              TypeString(type));
 
     barrier = ArenaNew<TypeBarrier>(cx->compartment->pool);
     barrier->target = target;
     barrier->type = type;
 
     barrier->next = code.typeBarriers;
     code.typeBarriers = barrier;
 }
@@ -2638,18 +2677,19 @@ TypeObject::addProperty(JSContext *cx, j
     Property *base = cx->new_<Property>(id);
     if (!base) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
     *pprop = base;
 
-    InferSpew(ISpewOps, "typeSet: T%p property %s %s",
-              &base->types, name(), TypeIdString(id));
+    InferSpew(ISpewOps, "typeSet: %sT%p%s property %s %s",
+              InferSpewColor(&base->types), &base->types, InferSpewColorReset(),
+              name(), TypeIdString(id));
 
     if (!JSID_IS_EMPTY(id)) {
         /* Check all transitive instances for this property. */
         if (instanceList)
             storeToInstances(cx, base);
 
         /* Pull in this property from all prototypes up the chain. */
         getFromPrototypes(cx, base);
@@ -3124,25 +3164,28 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             /*
              * The phi nodes at join points should all be unique, and every phi
              * node created should be in the phiValues list on some bytecode.
              */
             if (!state.phiNodes.append(newv->value.phiNode()))
                 return false;
             TypeSet &types = newv->value.phiNode()->types;
             types.setIntermediate();
-            InferSpew(ISpewOps, "typeSet: T%p phi #%u:%05u:%u", &types,
+            InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u",
+                      InferSpewColor(&types), &types, InferSpewColorReset(),
                       script->id(), offset, newv->slot);
             newv++;
         }
     }
 
     for (unsigned i = 0; i < defCount; i++) {
         pushed[i].setIntermediate();
-        InferSpew(ISpewOps, "typeSet: T%p pushed%u #%u:%05u", &pushed[i], i, script->id(), offset);
+        InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u",
+                  InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(),
+                  i, script->id(), offset);
     }
 
     /* Add type constraints for the various opcodes. */
     switch (op) {
 
         /* Nop bytecodes. */
       case JSOP_POP:
       case JSOP_NOP:
@@ -5026,26 +5069,38 @@ TypeScript::makeTypeArray(JSContext *cx)
     if (!typeArray) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
 #ifdef DEBUG
     unsigned id = script()->id();
     for (unsigned i = 0; i < script()->nTypeSets; i++)
-        InferSpew(ISpewOps, "typeSet: T%p bytecode%u #%u", &typeArray[i], i, id);
-    InferSpew(ISpewOps, "typeSet: T%p return #%u", returnTypes(), id);
-    InferSpew(ISpewOps, "typeSet: T%p this #%u", thisTypes(), id);
+        InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
+                  InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
+                  i, id);
+    InferSpew(ISpewOps, "typeSet: %sT%p%s return #%u",
+              InferSpewColor(returnTypes()), returnTypes(), InferSpewColorReset(),
+              id);
+    InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
+              InferSpewColor(thisTypes()), thisTypes(), InferSpewColorReset(),
+              id);
     unsigned nargs = script()->fun ? script()->fun->nargs : 0;
     for (unsigned i = 0; i < nargs; i++)
-        InferSpew(ISpewOps, "typeSet: T%p arg%u #%u", argTypes(i), i, id);
+        InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u",
+                  InferSpewColor(argTypes(i)), argTypes(i), InferSpewColorReset(),
+                  i, id);
     for (unsigned i = 0; i < script()->nfixed; i++)
-        InferSpew(ISpewOps, "typeSet: T%p local%u #%u", localTypes(i), i, id);
+        InferSpew(ISpewOps, "typeSet: %sT%p%s local%u #%u",
+                  InferSpewColor(localTypes(i)), localTypes(i), InferSpewColorReset(),
+                  i, id);
     for (unsigned i = 0; i < script()->bindings.countUpvars(); i++)
-        InferSpew(ISpewOps, "typeSet: T%p upvar%u #%u", upvarTypes(i), i, id);
+        InferSpew(ISpewOps, "typeSet: %sT%p%s upvar%u #%u",
+                  InferSpewColor(upvarTypes(i)), upvarTypes(i), InferSpewColorReset(),
+                  i, id);
 #endif
 
     return true;
 }
 
 bool
 JSScript::typeSetFunction(JSContext *cx, JSFunction *fun)
 {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1033,31 +1033,38 @@ struct TypeCompartment
 enum SpewChannel {
     ISpewOps,      /* ops: New constraints and types. */
     ISpewResult,   /* result: Final type sets. */
     SPEW_COUNT
 };
 
 #ifdef DEBUG
 
+inline const char * InferSpewColorReset() { return "\x1b[0m"; }
+const char * InferSpewColor(TypeConstraint *constraint);
+const char * InferSpewColor(TypeSet *types);
+
 void InferSpew(SpewChannel which, const char *fmt, ...);
 const char * TypeString(jstype type);
 
 /*
  * Check that a type set contains value. Unlike TypeSet::hasType, this returns
  * true if type has had its prototype mutated and another object with unknown
  * properties is in the type set.
  */
 bool TypeMatches(JSContext *cx, TypeSet *types, jstype type);
 
 /* Check that the type property for id in obj contains value. */
 bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
 
 #else
 
+inline const char * InferSpewColorReset() { return NULL; }
+inline const char * InferSpewColor(TypeConstraint *constraint) { return NULL; }
+inline const char * InferSpewColor(TypeSet *types) { return NULL; }
 inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
 inline const char * TypeString(jstype type) { return NULL; }
 
 #endif
 
 /* Print a warning, dump state and abort the program. */
 void TypeFailure(JSContext *cx, const char *fmt, ...);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -723,17 +723,19 @@ TypeScript::setUpvar(JSContext *cx, unsi
 
 inline void
 TypeCompartment::addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, jstype type)
 {
     JS_ASSERT(this == &cx->compartment->types);
     JS_ASSERT(type);
     JS_ASSERT(!cx->runtime->gcRunning);
 
-    InferSpew(ISpewOps, "pending: C%p %s", constraint, TypeString(type));
+    InferSpew(ISpewOps, "pending: %sC%p%s %s",
+              InferSpewColor(constraint), constraint, InferSpewColorReset(),
+              TypeString(type));
 
     if (pendingCount == pendingCapacity)
         growPendingArray(cx);
 
     PendingWork &pending = pendingArray[pendingCount++];
     pending.constraint = constraint;
     pending.source = source;
     pending.type = type;
@@ -749,18 +751,19 @@ TypeCompartment::resolvePending(JSContex
         return;
     }
 
     resolving = true;
 
     /* Handle all pending type registrations. */
     while (pendingCount) {
         const PendingWork &pending = pendingArray[--pendingCount];
-        InferSpew(ISpewOps, "resolve: C%p %s",
-                  pending.constraint, TypeString(pending.type));
+        InferSpew(ISpewOps, "resolve: %sC%p%s %s",
+                  InferSpewColor(pending.constraint), pending.constraint,
+                  InferSpewColorReset(), TypeString(pending.type));
         pending.constraint->newType(cx, pending.source, pending.type);
     }
 
     resolving = false;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeSet
@@ -1013,24 +1016,27 @@ TypeSet::addType(JSContext *cx, jstype t
                                   (cx, objectSet, objectCount, object, intermediate());
         if (!pentry || *pentry)
             return;
         *pentry = object;
 
         if (objectCount > 1) {
             object->contribution += (objectCount - 1) * (objectCount - 1);
             if (object->contribution >= TypeObject::CONTRIBUTION_LIMIT) {
-                InferSpew(ISpewOps, "limitUnknown: T%p", this);
+                InferSpew(ISpewOps, "limitUnknown: %sT%p%s",
+                          InferSpewColor(this), this, InferSpewColorReset());
                 type = TYPE_UNKNOWN;
                 markUnknown(cx);
             }
         }
     }
 
-    InferSpew(ISpewOps, "addType: T%p %s", this, TypeString(type));
+    InferSpew(ISpewOps, "addType: %sT%p%s %s",
+              InferSpewColor(this), this, InferSpewColorReset(),
+              TypeString(type));
 
     /* Propagate the type to all constraints. */
     TypeConstraint *constraint = constraintList;
     while (constraint) {
         JS_ASSERT_IF(!constraint->persistentObject(),
                      constraint->script->compartment == cx->compartment);
         cx->compartment->types.addPending(cx, constraint, this, type);
         constraint = constraint->next;