Fix property cache fill to recompute protoIndex to handle XBL and other JS_SetPrototype users (418139, r/a=shaver).
authorbrendan@mozilla.org
Sat, 01 Mar 2008 20:06:33 -0800
changeset 12472 a0684d4378fa99ad832f7092b335a6843756ac63
parent 12471 dfb1da7768bf6a01762813a34eba3c3bb43a9225
child 12473 fc5fb1eb6c094470129f40d7b65af0e4ad44156c
push idunknown
push userunknown
push dateunknown
bugs418139
milestone1.9b4pre
Fix property cache fill to recompute protoIndex to handle XBL and other JS_SetPrototype users (418139, r/a=shaver).
js/src/jsinterp.c
--- a/js/src/jsinterp.c
+++ b/js/src/jsinterp.c
@@ -128,17 +128,42 @@ js_FillPropertyCache(JSContext *cx, JSOb
      */
     scope = OBJ_SCOPE(pobj);
     JS_ASSERT(scope->object == pobj);
     if (!SCOPE_HAS_PROPERTY(scope, sprop)) {
         PCMETER(cache->oddfills++);
         return;
     }
 
-    /* Check for overdeep scope and prototype chain. */
+    /*
+     * Check for overdeep scope and prototype chain. Because resolve, getter,
+     * and setter hooks can change the prototype chain using JS_SetPrototype
+     * after js_LookupPropertyWithFlags has returned the nominal protoIndex,
+     * we have to validate protoIndex if it is non-zero. If it is zero, then
+     * we know thanks to the SCOPE_HAS_PROPERTY test above, and from the fact
+     * that obj == pobj, that protoIndex is invariant.
+     *
+     * The scopeIndex can't be wrong. We require JS_SetParent calls to happen
+     * before any running script might consult a parent-linked scope chain. If
+     * this requirement is not satisfied, the fill in progress will never hit,
+     * but vcap vs. scope shape tests ensure nothing malfunctions.
+     */
+    JS_ASSERT_IF(scopeIndex == 0 && protoIndex == 0, obj == pobj);
+    if (protoIndex != 0) {
+        JSObject *tmp;
+
+        JS_ASSERT(pobj != obj);
+        protoIndex = 1;
+        tmp = obj;
+        while ((tmp = OBJ_GET_PROTO(cx, tmp)) != NULL) {
+            if (tmp == pobj)
+                break;
+            ++protoIndex;
+        }
+    }
     if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) {
         PCMETER(cache->longchains++);
         return;
     }
 
     /*
      * Optimize the cached vword based on our parameters and the current pc's
      * opcode format flags.