Bug 616744 - Add GetElement PIC for arguments objects r=dvander

This commit is contained in:
Tom Schuster 2011-07-27 15:39:55 +02:00
parent fe992a7ed5
commit b6f9f332e2
5 changed files with 179 additions and 0 deletions

View File

@ -0,0 +1,23 @@
function f() {
var args = arguments, r;
for (var i = 0; i < args.length; i++)
r = args[i];
return r;
}
assertEq(f.apply(null, [1, 2, 3, 4, 5, 6]), 6)
assertEq(f.apply(null, [1, 2, 3, 4, 5]), 5)
assertEq(f.apply(null, [1, 2, 3, 4]), 4)
function g(arg) {
var r;
for (var i = 0; i < arg.length; i++)
r = arg[i];
return r;
}
assertEq(g((function () arguments).call(null, 1, 2, 3)), 3);
assertEq(g(new Float32Array(3)), 0.0);
assertEq(g([1, 2, 3, 4]), 4);

View File

@ -2297,6 +2297,154 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
return Lookup_Cacheable; return Lookup_Cacheable;
} }
LookupStatus
GetElementIC::attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp)
{
if (!v.isInt32())
return disable(cx, "arguments object with non-integer key");
if (op == JSOP_CALLELEM)
return disable(cx, "arguments object with call");
JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
Assembler masm;
Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
masm.move(objReg, typeReg);
masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)),
objReg);
Jump overridden = masm.branchTest32(Assembler::NonZero, objReg,
Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), objReg);
Jump outOfBounds;
if (idRemat.isConstant()) {
outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
} else {
outOfBounds = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
}
masm.loadPayload(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
if (idRemat.isConstant()) {
Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
masm.loadTypeTag(slot, objReg);
} else {
BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE,
offsetof(ArgumentsData, slots));
masm.loadTypeTag(slot, objReg);
}
Jump holeCheck = masm.branchPtr(Assembler::Equal, objReg, ImmType(JSVAL_TYPE_MAGIC));
Address privateData(typeReg, offsetof(JSObject, privateData));
Jump liveArguments = masm.branchPtr(Assembler::NotEqual, privateData, ImmPtr(0));
masm.loadPrivate(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::DATA_SLOT)), objReg);
if (idRemat.isConstant()) {
Address slot(objReg, offsetof(ArgumentsData, slots) + v.toInt32() * sizeof(Value));
masm.loadValueAsComponents(slot, typeReg, objReg);
} else {
BaseIndex slot(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE,
offsetof(ArgumentsData, slots));
masm.loadValueAsComponents(slot, typeReg, objReg);
}
Jump done = masm.jump();
liveArguments.linkTo(masm.label(), &masm);
masm.loadPtr(privateData, typeReg);
Address fun(typeReg, StackFrame::offsetOfExec());
masm.loadPtr(fun, objReg);
Address nargs(objReg, offsetof(JSFunction, nargs));
masm.load16(nargs, objReg);
Jump notFormalArg;
if (idRemat.isConstant())
notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, Imm32(v.toInt32()));
else
notFormalArg = masm.branch32(Assembler::BelowOrEqual, objReg, idRemat.dataReg());
masm.lshift32(Imm32(3), objReg); /* nargs << 3 == nargs * sizeof(Value) */
masm.subPtr(objReg, typeReg); /* fp - numFormalArgs => start of formal args */
Label loadFromStack = masm.label();
masm.move(typeReg, objReg);
if (idRemat.isConstant()) {
Address frameEntry(objReg, v.toInt32() * sizeof(Value));
masm.loadValueAsComponents(frameEntry, typeReg, objReg);
} else {
BaseIndex frameEntry(objReg, idRemat.dataReg(), Assembler::JSVAL_SCALE);
masm.loadValueAsComponents(frameEntry, typeReg, objReg);
}
Jump done2 = masm.jump();
notFormalArg.linkTo(masm.label(), &masm);
masm.push(typeReg);
Address argsObject(typeReg, StackFrame::offsetOfArgs());
masm.loadPtr(argsObject, typeReg);
masm.load32(Address(typeReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)),
typeReg);
masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), typeReg);
/* This bascially does fp - (numFormalArgs + numActualArgs + 2) */
masm.addPtr(typeReg, objReg);
masm.addPtr(Imm32(2), objReg);
masm.lshiftPtr(Imm32(3), objReg);
masm.pop(typeReg);
masm.subPtr(objReg, typeReg);
masm.jump(loadFromStack);
PICLinker buffer(masm, *this);
if (!buffer.init(cx))
return error(cx);
if (!buffer.verifyRange(cx->fp()->jit()))
return disable(cx, "code memory is out of range");
buffer.link(claspGuard, slowPathStart);
buffer.link(overridden, slowPathStart);
buffer.link(outOfBounds, slowPathStart);
buffer.link(holeCheck, slowPathStart);
buffer.link(done, fastPathRejoin);
buffer.link(done2, fastPathRejoin);
CodeLocationLabel cs = buffer.finalizeCodeAddendum();
JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress());
Repatcher repatcher(cx->fp()->jit());
repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs);
JS_ASSERT(!shouldPatchUnconditionalClaspGuard());
JS_ASSERT(!inlineClaspGuardPatched);
inlineClaspGuardPatched = true;
stubsGenerated++;
if (stubsGenerated == MAX_GETELEM_IC_STUBS)
disable(cx, "max stubs reached");
disable(cx, "generated arguments stub");
if (!obj->getProperty(cx, id, vp))
return Lookup_Error;
return Lookup_Cacheable;
}
#if defined JS_POLYIC_TYPED_ARRAY #if defined JS_POLYIC_TYPED_ARRAY
LookupStatus LookupStatus
GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp) GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp)

View File

@ -296,6 +296,8 @@ struct GetElementIC : public BasePolyIC {
LookupStatus update(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp); LookupStatus update(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp);
LookupStatus attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id, LookupStatus attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid id,
Value *vp); Value *vp);
LookupStatus attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid id,
Value *vp);
LookupStatus attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, LookupStatus attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id,
Value *vp); Value *vp);
LookupStatus disable(JSContext *cx, const char *reason); LookupStatus disable(JSContext *cx, const char *reason);

View File

@ -62,6 +62,7 @@ struct VMFrame;
namespace mjit { namespace mjit {
namespace ic { namespace ic {
struct PICInfo; struct PICInfo;
struct GetElementIC;
/* Aargh, Windows. */ /* Aargh, Windows. */
#ifdef GetProp #ifdef GetProp
@ -181,6 +182,7 @@ class ArgumentsObject : public ::JSObject
#endif #endif
#ifdef JS_POLYIC #ifdef JS_POLYIC
friend class ::GetPropCompiler; friend class ::GetPropCompiler;
friend class mjit::ic::GetElementIC;
#endif #endif
void setInitialLength(uint32 length); void setInitialLength(uint32 length);

View File

@ -1037,6 +1037,10 @@ class StackFrame
return offsetof(StackFrame, exec); return offsetof(StackFrame, exec);
} }
static size_t offsetOfArgs() {
return offsetof(StackFrame, args);
}
void *addressOfArgs() { void *addressOfArgs() {
return &args; return &args;
} }