Fix prototype guards on array hole ICs (bug 615440, r=dmandelin).
authorDavid Anderson <danderson@mozilla.com>
Tue, 30 Nov 2010 17:14:01 -0800
changeset 58694 e5a107d913777c2fbd34a3a8c1ed980e18272cf6
parent 58693 77af2eebbdbdef9a5ec8c0c1c343697c678b3d16
child 58695 a687492cff3dad319c00fc45f429d251e9972a50
push id17407
push userrsayre@mozilla.com
push dateMon, 06 Dec 2010 22:03:37 +0000
treeherdermozilla-central@2f96714fd6d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmandelin
bugs615440
milestone2.0b8pre
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
Fix prototype guards on array hole ICs (bug 615440, r=dmandelin).
js/src/jit-test/tests/jaeger/bug615440.js
js/src/methodjit/PolyIC.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug615440.js
@@ -0,0 +1,5 @@
+Array.prototype.__proto__ = null;
+for (var r = 0; r < 3; ++r) [][0] = 1;
+
+// Don't crash.
+
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -2368,34 +2368,31 @@ SetElementIC::attachHoleStub(JSContext *
     JS_ASSERT((jsuint)keyval >= obj->getDenseArrayCapacity() ||
               obj->getDenseArrayElement(keyval).isMagic(JS_ARRAY_HOLE));
 
     if (js_PrototypeHasIndexedProperties(cx, obj))
         return disable(cx, "prototype has indexed properties");
 
     Assembler masm;
 
-    // Test for indexed properties in Array.prototype. It is safe to bake in
-    // this pointer because changing __proto__ will slowify.
-    JSObject *arrayProto = obj->getProto();
-    masm.move(ImmPtr(arrayProto), objReg);
-    Jump extendedArray = masm.branchTest32(Assembler::NonZero,
-                                           Address(objReg, offsetof(JSObject, flags)),
-                                           Imm32(JSObject::INDEXED));
-
-    // Text for indexed properties in Object.prototype. Guard that
-    // Array.prototype doesn't change, too.
-    JSObject *objProto = arrayProto->getProto();
-    Jump sameProto = masm.branchPtr(Assembler::NotEqual,
-                                    Address(objReg, offsetof(JSObject, proto)),
-                                    ImmPtr(objProto));
-    masm.move(ImmPtr(objProto), objReg);
-    Jump extendedObject = masm.branchTest32(Assembler::NonZero,
-                                            Address(objReg, offsetof(JSObject, flags)),
-                                            Imm32(JSObject::INDEXED));
+    Vector<Jump, 4> fails(cx);
+
+    // Test for indexed properties in Array.prototype. We test each shape
+    // along the proto chain. This affords us two optimizations:
+    //  1) Loading the prototype can be avoided because the shape would change;
+    //     instead we can bake in their identities.
+    //  2) We only have to test the shape, rather than INDEXED.
+    for (JSObject *pobj = obj->getProto(); pobj; pobj = pobj->getProto()) {
+        if (!pobj->isNative())
+            return disable(cx, "non-native array prototype");
+        masm.move(ImmPtr(pobj), objReg);
+        Jump j = masm.guardShape(objReg, pobj);
+        if (!fails.append(j))
+            return error(cx);
+    }
 
     // Restore |obj|.
     masm.rematPayload(StateRemat::FromInt32(objRemat), objReg);
 
     // Guard against negative indices.
     MaybeJump keyGuard;
     if (!hasConstantKey)
         keyGuard = masm.branch32(Assembler::LessThan, keyReg, Imm32(0));
@@ -2433,19 +2430,18 @@ SetElementIC::attachHoleStub(JSContext *
     execPool = buffer.init(cx);
     if (!execPool)
         return error(cx);
 
     if (!buffer.verifyRange(cx->fp()->jit()))
         return disable(cx, "code memory is out of range");
 
     // Patch all guards.
-    buffer.link(extendedArray, slowPathStart);
-    buffer.link(sameProto, slowPathStart);
-    buffer.link(extendedObject, slowPathStart);
+    for (size_t i = 0; i < fails.length(); i++)
+        buffer.link(fails[i], slowPathStart);
     buffer.link(done, fastPathRejoin);
 
     CodeLocationLabel cs = buffer.finalize();
     JaegerSpew(JSpew_PICs, "generated dense array hole stub at %p\n", cs.executableAddress());
 
     Repatcher repatcher(cx->fp()->jit());
     repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), cs);
     inlineHoleGuardPatched = true;