[INFER] More robust handling of constant object frame entries.

This commit is contained in:
Brian Hackett 2011-03-22 05:27:03 -07:00
parent c633bccba3
commit c4cfa981d7
4 changed files with 105 additions and 31 deletions

View File

@ -2372,19 +2372,10 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_UNBRANDTHIS)
BEGIN_CASE(JSOP_GETGLOBAL)
jsop_getglobal(GET_SLOTNO(PC));
END_CASE(JSOP_GETGLOBAL)
BEGIN_CASE(JSOP_CALLGLOBAL)
{
JSObject *singleton = pushedSingleton(0);
uint32 slot = GET_SLOTNO(PC);
if (singleton && !globalObj->getSlot(slot).isUndefined())
frame.push(ObjectValue(*singleton));
else
jsop_getglobal(slot);
frame.push(UndefinedValue());
}
jsop_getglobal(GET_SLOTNO(PC));
if (op == JSOP_CALLGLOBAL)
frame.push(UndefinedValue());
END_CASE(JSOP_GETGLOBAL)
default:
@ -2492,6 +2483,12 @@ mjit::Compiler::jsop_getglobal(uint32 index)
JS_ASSERT(globalObj);
uint32 slot = script->getGlobalSlot(index);
JSObject *singleton = pushedSingleton(0);
if (singleton && !globalObj->getSlot(slot).isUndefined()) {
frame.push(ObjectValue(*singleton));
return;
}
RegisterID reg = frame.allocReg();
Address address = masm.objSlotRef(globalObj, reg, slot);
frame.push(address, knownPushedType(0));
@ -2507,7 +2504,7 @@ mjit::Compiler::jsop_getglobal(uint32 index)
stubcc.linkExit(jump, Uses(0));
stubcc.leave();
OOL_STUBCALL(stubs::UndefinedHelper);
stubcc.rejoin(Changes(0));
stubcc.rejoin(Changes(1));
}
}
@ -2919,15 +2916,9 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
bool newType = callingNew && cx->typeInferenceEnabled() && types::UseNewType(cx, script, PC);
/*
* Currently, constant values are not functions, so don't even try to
* optimize. This lets us assume that callee/this have regs below.
*/
#ifdef JS_MONOIC
if (debugMode() || newType ||
origCallee->isConstant() || origCallee->isNotType(JSVAL_TYPE_OBJECT) ||
(lowerFunCallOrApply &&
(origThis->isConstant() || origThis->isNotType(JSVAL_TYPE_OBJECT)))) {
if (debugMode() || newType || origCallee->isNotType(JSVAL_TYPE_OBJECT) ||
(lowerFunCallOrApply && origThis->isNotType(JSVAL_TYPE_OBJECT))) {
#endif
if (applyTricks == LazyArgsObj) {
/* frame.pop() above reset us to pre-JSOP_ARGUMENTS state */
@ -2946,6 +2937,10 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
#ifdef JS_MONOIC
}
frame.forgetConstantData(origCallee);
if (lowerFunCallOrApply)
frame.forgetConstantData(origThis);
/* Initialized by both branches below. */
CallGenInfo callIC(PC);
CallPatchInfo callPatch;
@ -3226,8 +3221,14 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
callPatches.append(uncachedCallPatch);
if (!lowerFunCallOrApply && recompiling) {
/* Recompiled from inlined native slow path. */
if (!callingNew) {
OOL_STUBCALL(stubs::SlowCall);
stubcc.rejoin(Changes(1));
}
/* Recompiled uncached call to cached call. */
OOL_STUBCALL(stubs::UncachedCall);
OOL_STUBCALL(callingNew ? stubs::UncachedNew : stubs::UncachedCall);
stubcc.rejoin(Changes(1));
}
@ -3455,6 +3456,8 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType,
return true;
}
frame.forgetConstantData(top);
/*
* These two must be loaded first. The objReg because the string path
* wants to read it, and the shapeReg because it could cause a spill that
@ -3829,6 +3832,19 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
bool
mjit::Compiler::testSingletonProperty(JSObject *obj, jsid id)
{
/*
* We would like to completely no-op property/global accesses which can
* produce only a particular JSObject or undefined, provided we can
* determine the pushed value must not be undefined (or, if it could be
* undefined, a recompilation will be triggered).
*
* If the access definitely goes through obj, either directly or on the
* prototype chain, then if obj has a defined property now, and the
* property has a default or method shape, the only way it can produce
* undefined in the future is if it is deleted. Deletion causes type
* properties to be explicitly marked with undefined.
*/
if (!obj->isNative())
return false;
if (obj->getClass()->ops.lookupProperty)
@ -3988,6 +4004,8 @@ mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
pic.typeReg = Registers::ReturnReg;
}
frame.forgetConstantData(lhs);
/* Get the object into a mutable register. */
RegisterID objReg = frame.copyDataIntoReg(lhs);
pic.objReg = objReg;
@ -4089,14 +4107,26 @@ mjit::Compiler::jsop_name(JSAtom *atom, JSValueType type)
/* Always test for undefined. */
Jump undefinedGuard = masm.testUndefined(Assembler::Equal, pic.shapeReg);
frame.pushRegs(pic.shapeReg, pic.objReg, type);
/*
* We can't optimize away the PIC for the NAME access itself, but if we've
* only seen a single value pushed by this access, mark it as such and
* recompile if a different value becomes possible.
*/
JSObject *singleton = pushedSingleton(0);
if (singleton) {
frame.push(ObjectValue(*singleton));
frame.freeReg(pic.shapeReg);
frame.freeReg(pic.objReg);
} else {
frame.pushRegs(pic.shapeReg, pic.objReg, type);
}
stubcc.rejoin(Changes(1));
stubcc.linkExit(undefinedGuard, Uses(0));
stubcc.leave();
OOL_STUBCALL(stubs::UndefinedHelper);
stubcc.rejoin(Changes(0));
stubcc.rejoin(Changes(1));
pics.append(pic);
}
@ -4116,6 +4146,8 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
stubcc.linkExit(notObject, Uses(1));
}
frame.forgetConstantData(fe);
RESERVE_IC_SPACE(masm);
pic.shapeReg = frame.allocReg();
@ -4156,7 +4188,7 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
stubcc.linkExit(undefinedGuard, Uses(0));
stubcc.leave();
OOL_STUBCALL(stubs::UndefinedHelper);
stubcc.rejoin(Changes(0));
stubcc.rejoin(Changes(1));
pics.append(pic);
return true;
@ -4593,6 +4625,8 @@ mjit::Compiler::iter(uintN flags)
stubcc.linkExit(notObject, Uses(1));
}
frame.forgetConstantData(fe);
RegisterID reg = frame.tempRegForData(fe);
frame.pinReg(reg);
@ -4890,16 +4924,13 @@ mjit::Compiler::jsop_getgname(uint32 index, JSValueType type)
return;
}
/*
* Optimize singletons like Math for JSOP_CALLPROP.
* :FIXME: Fix other ops to support constant objects.
*/
/* Optimize singletons like Math for JSOP_CALLPROP. */
JSObject *obj = pushedSingleton(0);
if (obj && *(PC+JSOP_GETGNAME_LENGTH) == JSOP_CALLPROP &&
testSingletonProperty(globalObj, ATOM_TO_JSID(atom))) {
if (obj && testSingletonProperty(globalObj, ATOM_TO_JSID(atom))) {
frame.push(ObjectValue(*obj));
return;
}
#if defined JS_MONOIC
jsop_bindgname();
@ -4995,6 +5026,19 @@ mjit::Compiler::jsop_callgname_epilogue()
return;
}
/* Paths for known object callee. */
if (fval->isConstant()) {
JSObject *obj = &fval->getValue().toObject();
if (obj->getParent() == globalObj) {
frame.push(UndefinedValue());
} else {
prepareStubCall(Uses(1));
INLINE_STUBCALL(stubs::PushImplicitThisForGlobal);
frame.pushSynced(JSVAL_TYPE_UNKNOWN);
}
return;
}
/*
* Optimized version. This inlines the common case, calling a
* (non-proxied) function that has the same global as the current
@ -5197,6 +5241,9 @@ mjit::Compiler::jsop_instanceof()
stubcc.linkExit(j, Uses(2));
}
frame.forgetConstantData(lhs);
frame.forgetConstantData(rhs);
RegisterID obj = frame.tempRegForData(rhs);
Jump notFunction = masm.testFunction(Assembler::NotEqual, obj);
stubcc.linkExit(notFunction, Uses(2));

View File

@ -580,6 +580,8 @@ mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp f
if (lhsKind != types::OBJECT_UNKNOWN && rhsKind != types::OBJECT_UNKNOWN) {
/* :TODO: Merge with jsop_relational_int? */
JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
frame.forgetConstantData(lhs);
frame.forgetConstantData(rhs);
Assembler::Condition cond = GetCompareCondition(op, fused);
if (target) {
fixDoubleTypes(Uses(2));
@ -1270,6 +1272,8 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
return true;
}
frame.forgetConstantData(obj);
if (cx->typeInferenceEnabled()) {
types::TypeSet *types = frame.getTypeSet(obj);
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;
@ -1586,6 +1590,8 @@ mjit::Compiler::jsop_getelem(bool isCall)
return true;
}
frame.forgetConstantData(obj);
if (cx->typeInferenceEnabled()) {
types::TypeSet *types = frame.getTypeSet(obj);
types::ObjectKind kind = types ? types->getKnownObjectKind(cx, script) : types::OBJECT_UNKNOWN;

View File

@ -497,6 +497,20 @@ FrameState::tempRegForData(FrameEntry *fe)
return reg;
}
inline void
FrameState::forgetConstantData(FrameEntry *fe)
{
if (!fe->data.isConstant())
return;
JS_ASSERT(fe->isType(JSVAL_TYPE_OBJECT));
RegisterID reg = allocReg();
regstate(reg).associate(fe, RematInfo::DATA);
masm.move(JSC::MacroAssembler::ImmPtr(&fe->getValue().toObject()), reg);
fe->data.setRegister(reg);
}
inline JSC::MacroAssembler::FPRegisterID
FrameState::tempFPRegForData(FrameEntry *fe)
{

View File

@ -403,6 +403,13 @@ class FrameState
*/
inline RegisterID tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const;
/*
* If fe is a constant, allocate a register and forget its payload. This
* function is a stopgap to cover missing paths in the Compiler, uses of it
* should be fixed.
*/
inline void forgetConstantData(FrameEntry *fe);
/*
* Convert an integer to a double without applying
* additional Register pressure.