author | Tom Schuster <evilpies@gmail.com> |
Thu, 30 Dec 2010 13:25:03 -0600 | |
changeset 59970 | feb28ec64b743cbdbfb3d3283a19e072f258a926 |
parent 59969 | c5d43dfafcbc17707bed4c1849a68a72e2676e8b |
child 59971 | b139e168fbf00b363a15edca33ac10b935289176 |
push id | 17820 |
push user | cleary@mozilla.com |
push date | Tue, 04 Jan 2011 21:40:57 +0000 |
treeherder | mozilla-central@969691cfe40e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dvander |
bugs | 557353 |
milestone | 2.0b9pre |
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
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/pic/length_string_object.js @@ -0,0 +1,36 @@ +//length, string, object + +var expected = "3,6,4,3,6,4,3,6,4,3,6,4,"; +var actual = ''; + +function f() { + var ss = [new String("abc"), new String("foobar"), new String("quux")]; + + for (var i = 0; i < 12; ++i) { + actual += ss[i%3].length + ','; + } +} + +f(); + +assertEq(actual, expected); + + +function g(s) { + return new String(s).length; +} + +assertEq(g("x"), 1); // Warm-up +assertEq(g("x"), 1); // Create IC +assertEq(g("x"), 1); // Test IC + +function h(s) { + var x = new String(s); + for (var i = 0; i < 100; i++) + x[i] = i; + return x.length; +} + +assertEq(h("x"), 1); +assertEq(h("x"), 1); +assertEq(h("x"), 1);
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -295,16 +295,17 @@ struct JSObject : js::gc::Cell { /* * TraceRecorder must be a friend because it generates code that * manipulates JSObjects, which requires peeking under any encapsulation. * ValidateWriter must be a friend because it works in tandem with * TraceRecorder. */ friend class js::TraceRecorder; friend class nanojit::ValidateWriter; + friend class GetPropCompiler; /* * Private pointer to the last added property and methods to manipulate the * list it links among properties in this scope. The {remove,insert} pair * for DictionaryProperties assert that the scope is in dictionary mode and * any reachable properties are flagged as dictionary properties. * * NB: these private methods do *not* update this scope's shape to track
--- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -821,17 +821,18 @@ class GetPropCompiler : public PICStubCo Assembler masm; Jump notArgs = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg); masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)), pic.objReg); masm.move(pic.objReg, pic.shapeReg); - Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, Imm32(1)); + Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, + Imm32(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT)); masm.rshift32(Imm32(JSObject::ARGS_PACKED_BITS_COUNT), pic.objReg); masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); Jump done = masm.jump(); PICLinker buffer(masm, pic); if (!buffer.init(cx)) return error(); @@ -889,16 +890,51 @@ class GetPropCompiler : public PICStubCo patchPreviousToHere(start); disable("array length done"); return Lookup_Cacheable; } + LookupStatus generateStringObjLengthStub() + { + Assembler masm; + + Jump notStringObj = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass()); + masm.loadPayload(Address(pic.objReg, JSObject::getFixedSlotOffset( + JSObject::JSSLOT_PRIMITIVE_THIS)), pic.objReg); + masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg); + masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg); + masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg); + Jump done = masm.jump(); + + PICLinker buffer(masm, pic); + if (!buffer.init(cx)) + return error(); + + if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) || + !buffer.verifyRange(f.jit())) { + return disable("code memory is out of range"); + } + + buffer.link(notStringObj, pic.slowPathStart); + buffer.link(done, pic.fastPathRejoin); + + CodeLocationLabel start = buffer.finalize(); + JaegerSpew(JSpew_PICs, "generate string object length stub at %p\n", + start.executableAddress()); + + patchPreviousToHere(start); + + disable("string object length done"); + + return Lookup_Cacheable; + } + LookupStatus generateStringCallStub() { JS_ASSERT(pic.hasTypeCheck()); JS_ASSERT(pic.kind == ic::PICInfo::CALL); if (!f.fp()->script()->compileAndGo) return disable("String.prototype without compile-and-go"); @@ -1657,28 +1693,35 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic LookupStatus status = cc.generateStringLengthStub(); if (status == Lookup_Error) THROW(); JSString *str = f.regs.sp[-1].toString(); f.regs.sp[-1].setInt32(str->length()); return; } else if (!f.regs.sp[-1].isPrimitive()) { JSObject *obj = &f.regs.sp[-1].toObject(); - if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden())) { + if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden()) || + obj->isString()) { GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledLengthIC); if (obj->isArray()) { LookupStatus status = cc.generateArrayLengthStub(); if (status == Lookup_Error) THROW(); f.regs.sp[-1].setNumber(obj->getArrayLength()); } else if (obj->isArguments()) { LookupStatus status = cc.generateArgsLengthStub(); if (status == Lookup_Error) THROW(); f.regs.sp[-1].setInt32(int32_t(obj->getArgsInitialLength())); + } else if (obj->isString()) { + LookupStatus status = cc.generateStringObjLengthStub(); + if (status == Lookup_Error) + THROW(); + JSString *str = obj->getPrimitiveThis().toString(); + f.regs.sp[-1].setInt32(str->length()); } return; } } atom = f.cx->runtime->atomState.lengthAtom; } JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);