mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] More robust handling of constant object frame entries.
This commit is contained in:
parent
c633bccba3
commit
c4cfa981d7
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user