Bug 495897 - Assertion failure: ti->typeMap.matches(ti_other->typeMap) with undeclared global. r=dvander
authorAndreas Gal <gal@uci.edu>
Tue, 02 Jun 2009 22:28:59 -0400
changeset 25867 ba731d4f9b0a9f83db1edc08047a420eaaca4c4a
parent 25866 17a92e7180ed0545b23e1fb1e9039c449618d3a8
child 25868 4484277f94346ea90e7df5afcb8cea9096548674
push id1645
push userrsayre@mozilla.com
push dateThu, 04 Jun 2009 16:54:53 +0000
reviewersdvander
bugs495897
milestone1.9.1pre
Bug 495897 - Assertion failure: ti->typeMap.matches(ti_other->typeMap) with undeclared global. r=dvander
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -661,16 +661,39 @@ getAnchor(JSTraceMonitor* tm, const void
         tm->vmfragments[h] = f;
     }
     f->anchor = f;
     f->root = f;
     f->kind = LoopTrace;
     return f;
 }
 
+#ifdef DEBUG
+static void
+ensureTreeIsUnique(JSTraceMonitor* tm, VMFragment* f, TreeInfo* ti)
+{
+    JS_ASSERT(f->root == f);
+    /*
+     * Check for duplicate entry type maps.  This is always wrong and hints at
+     * trace explosion since we are trying to stabilize something without
+     * properly connecting peer edges.
+     */
+    TreeInfo* ti_other;
+    for (Fragment* peer = getLoop(tm, f->ip, f->globalObj, f->globalShape, f->argc);
+         peer != NULL;
+         peer = peer->peer) {
+        if (!peer->code() || peer == f)
+            continue;
+        ti_other = (TreeInfo*)peer->vmprivate;
+        JS_ASSERT(ti_other);
+        JS_ASSERT(!ti->typeMap.matches(ti_other->typeMap));
+    }
+}
+#endif
+
 static void
 js_AttemptCompilation(JSContext *cx, JSTraceMonitor* tm, JSObject* globalObj, jsbytecode* pc,
                       uint32 argc)
 {
     /*
      * If we already permanently blacklisted the location, undo that.
      */
     JS_ASSERT(*(jsbytecode*)pc == JSOP_NOP || *(jsbytecode*)pc == JSOP_LOOP);
@@ -3772,30 +3795,17 @@ js_RecordTree(JSContext* cx, JSTraceMoni
     /* setup the VM-private treeInfo structure for this fragment */
     TreeInfo* ti = new (&gc) TreeInfo(f, globalSlots);
 
     /* capture the coerced type of each active slot in the type map */
     ti->typeMap.captureTypes(cx, *globalSlots, 0/*callDepth*/);
     ti->nStackTypes = ti->typeMap.length() - globalSlots->length();
 
 #ifdef DEBUG
-    /*
-     * Check for duplicate entry type maps.  This is always wrong and hints at
-     * trace explosion since we are trying to stabilize something without
-     * properly connecting peer edges.
-     */
-    TreeInfo* ti_other;
-    for (Fragment* peer = getLoop(tm, f->root->ip, globalObj, globalShape, argc); peer != NULL;
-         peer = peer->peer) {
-        if (!peer->code() || peer == f)
-            continue;
-        ti_other = (TreeInfo*)peer->vmprivate;
-        JS_ASSERT(ti_other);
-        JS_ASSERT(!ti->typeMap.matches(ti_other->typeMap));
-    }
+    ensureTreeIsUnique(tm, (VMFragment*)f, ti);
     ti->treeFileName = cx->fp->script->filename;
     ti->treeLineNumber = js_FramePCToLineNumber(cx, cx->fp);
     ti->treePCOffset = FramePCOffset(cx->fp);
 #endif
 
     /* determine the native frame layout at the entry point */
     unsigned entryNativeStackSlots = ti->nStackTypes;
     JS_ASSERT(entryNativeStackSlots == js_NativeStackSlots(cx, 0/*callDepth*/));
@@ -3811,16 +3821,28 @@ js_RecordTree(JSContext* cx, JSTraceMoni
                           ti->globalSlots->length(),
                           ti->typeMap.data(), NULL, outer, outerArgc)) {
         return false;
     }
 
     return true;
 }
 
+JS_REQUIRES_STACK static inline void
+markSlotUndemotable(JSContext* cx, TreeInfo* ti, unsigned slot)
+{
+    if (slot < ti->nStackTypes) {
+        oracle.markStackSlotUndemotable(cx, slot);
+        return;
+    }
+
+    uint16* gslots = ti->globalSlots->data();
+    oracle.markGlobalSlotUndemotable(cx, gslots[slot - ti->nStackTypes]);
+}
+
 JS_REQUIRES_STACK static inline bool
 isSlotUndemotable(JSContext* cx, TreeInfo* ti, unsigned slot)
 {
     if (slot < ti->nStackTypes)
         return oracle.isStackSlotUndemotable(cx, slot);
 
     uint16* gslots = ti->globalSlots->data();
     return oracle.isGlobalSlotUndemotable(cx, gslots[slot - ti->nStackTypes]);
@@ -3835,38 +3857,40 @@ js_AttemptToStabilizeTree(JSContext* cx,
         return false;
     }
 
     VMFragment* from = (VMFragment*)exit->from->root;
     TreeInfo* from_ti = (TreeInfo*)from->vmprivate;
 
     JS_ASSERT(exit->from->root->code());
 
-    /* Make sure any doubles are not accidentally undemoted */
-    uint8* m = getStackTypeMap(exit);
-    for (unsigned i = 0; i < exit->numStackSlots; i++) {
-        if (m[i] == JSVAL_DOUBLE)
-            oracle.markStackSlotUndemotable(cx, i);
-    }
-    m = getGlobalTypeMap(exit);
-    for (unsigned i = 0; i < exit->numGlobalSlots; i++) {
-        if (m[i] == JSVAL_DOUBLE)
-            oracle.markGlobalSlotUndemotable(cx, from_ti->globalSlots->data()[i]);
-    }
-
-    /* If this exit does not have enough globals, there might exist a peer with more globals that we
-     * can join to, but only if the parent's globals match.
+    /*
+     * The loop edge exit might not know about all types since the tree could have
+     * been further specialized since it was recorded. Fill in the missing types
+     * from the entry type map.
      */
-    m = getFullTypeMap(exit);
-    if (exit->numGlobalSlots < from_ti->nGlobalTypes()) {
+    uint8* m = getFullTypeMap(exit);
+    unsigned ngslots = exit->numGlobalSlots;
+    if (ngslots < from_ti->nGlobalTypes()) {
         uint32 partial = exit->numStackSlots + exit->numGlobalSlots;
         m = (uint8*)alloca(from_ti->typeMap.length());
         memcpy(m, getFullTypeMap(exit), partial);
         memcpy(m + partial, from_ti->globalTypeMap() + exit->numGlobalSlots,
                from_ti->nGlobalTypes() - exit->numGlobalSlots);
+        ngslots = from_ti->nGlobalTypes();
+    }
+    JS_ASSERT(exit->numStackSlots + ngslots == from_ti->typeMap.length());
+
+    /*
+     * If we see any doubles along the loop edge, mark those slots undemotable
+     * since we know now for a fact that they can contain doubles.
+     */
+    for (unsigned i = 0; i < from_ti->typeMap.length(); i++) {
+        if (m[i] == JSVAL_DOUBLE)
+            markSlotUndemotable(cx, from_ti, i);
     }
 
     bool bound = false;
     for (Fragment* f = from->first; f != NULL; f = f->peer) {
         if (!f->code())
             continue;
         TreeInfo* ti = (TreeInfo*)f->vmprivate;
         JS_ASSERT(exit->numStackSlots == ti->nStackTypes);
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -5100,16 +5100,29 @@ test(testGetThis);
 
 function testArrayNamedProp() {
     for (var x = 0; x < 10; ++x) { [4].sort-- }
     return "ok";
 }
 testArrayNamedProp.expected = "ok";
 test(testArrayNamedProp);
 
+function testUndemoteLateGlobalSlots() {
+    for each (aaa in ["", "", 0/0, ""]) {
+        ++aaa;
+        for each (bbb in [0, "", aaa, "", 0, "", 0/0]) {
+        }
+    }
+    delete aaa;
+    delete bbb;
+    return "ok";
+}
+testUndemoteLateGlobalSlots.expected = "ok";
+test(testUndemoteLateGlobalSlots);
+
 /*****************************************************************************
  *                                                                           *
  *  _____ _   _  _____ ______ _____ _______                                  *
  * |_   _| \ | |/ ____|  ____|  __ \__   __|                                 *
  *   | | |  \| | (___ | |__  | |__) | | |                                    *
  *   | | | . ` |\___ \|  __| |  _  /  | |                                    *
  *  _| |_| |\  |____) | |____| | \ \  | |                                    *
  * |_____|_| \_|_____/|______|_|  \_\ |_|                                    *