diff --git a/js/src/jit-test/tests/jaeger/bug615440.js b/js/src/jit-test/tests/jaeger/bug615440.js new file mode 100644 index 000000000000..1ed4cd1c043d --- /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. + diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index 90892ea1567f..e959742c4579 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -2373,24 +2373,21 @@ SetElementIC::attachHoleStub(JSContext *cx, JSObject *obj, int32 keyval) 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)); + Vector fails(cx); - // 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)); + // 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); @@ -2438,9 +2435,8 @@ SetElementIC::attachHoleStub(JSContext *cx, JSObject *obj, int32 keyval) 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();