Bug 610583. When guarding on no indexed properties on our proto chain, use a branch exit, and reduce the number of guards involved. r=brendan
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 09 Nov 2010 21:46:18 -0500
changeset 57756 2fd60328c2b0d40107aa29f09ada785a4b44d6d4
parent 57755 805c1a5d5cc690aecad5ce81a09522ee7a34fa9a
child 57757 e8c612257ca5a044d5828fb51312eced6d737f02
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbrendan
bugs610583
milestone2.0b8pre
Bug 610583. When guarding on no indexed properties on our proto chain, use a branch exit, and reduce the number of guards involved. r=brendan
js/src/jstracer.cpp
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -9892,18 +9892,41 @@ TraceRecorder::guardPrototypeHasNoIndexe
 {
     /*
      * Guard that no object along the prototype chain has any indexed
      * properties which might become visible through holes in the array.
      */
     if (js_PrototypeHasIndexedProperties(cx, obj))
         return RECORD_STOP;
 
-    while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit))
+    JS_ASSERT(obj->isDenseArray());
+
+    /*
+     * Changing __proto__ on a dense array makes it slow, so we can just bake in
+     * the current prototype as the first prototype to test. This avoids an
+     * extra load when running the trace.
+     */
+    obj = obj->getProto();
+    JS_ASSERT(obj);
+
+    obj_ins = w.immpObjGC(obj);
+
+    /*
+     * Changing __proto__ on a native object changes its shape, and adding
+     * indexed properties changes shapes too.  And non-native objects never pass
+     * shape guards.  So it's enough to just guard on shapes up the proto chain;
+     * any change to the proto chain length will make us fail a guard before we
+     * run off the end of the proto chain.
+     */
+    do {
         CHECK_STATUS(guardShape(obj_ins, obj, obj->shape(), "guard(shape)", exit));
+        obj = obj->getProto();
+        obj_ins = w.ldpObjProto(obj_ins);
+    } while (obj);
+
     return RECORD_CONTINUE;
 }
 
 /*
  * Guard that the object stored in v has the ECMA standard [[DefaultValue]]
  * method. Several imacros require this.
  */
 JS_REQUIRES_STACK RecordingStatus
@@ -12831,17 +12854,22 @@ TraceRecorder::setElem(int lval_spindex,
                                         w.ldiValueTag(dslotAddr),
 #else
                                         w.q2i(w.rshuqN(w.ldq(dslotAddr), JSVAL_TAG_SHIFT)),
 #endif
                                         w.nameImmui(JSVAL_TAG_MAGIC)),
                                   "isHole");
         w.pauseAddingCSEValues();
         if (MaybeBranch mbr1 = w.jf(isHole_ins)) {
-            CHECK_STATUS_A(guardPrototypeHasNoIndexedProperties(obj, obj_ins, mismatchExit));
+            /*
+             * It's important that this use branchExit, not mismatchExit, since
+             * changes to shapes should just mean we compile a new branch, not
+             * throw the whole trace away.
+             */
+            CHECK_STATUS_A(guardPrototypeHasNoIndexedProperties(obj, obj_ins, branchExit));
             LIns* length_ins = w.lduiObjPrivate(obj_ins);
             if (MaybeBranch mbr2 = w.jt(w.ltui(idx_ins, length_ins))) {
                 LIns* newLength_ins = w.name(w.addiN(idx_ins, 1), "newLength");
                 w.stuiObjPrivate(obj_ins, newLength_ins);
                 w.label(mbr2);
             }
             w.label(mbr1);
         }