Optimize InstanceOfD when rhs is unique interface
We would normally have to load the class and do a whole bunch of other noise. Now we don't.
Esse commit está contido em:
@@ -534,14 +534,17 @@ D:Bool = OpNSame S0:Gen S1:Gen
|
||||
Perform comparisons with PHP semantics on S0 and S1, and put the
|
||||
result in D.
|
||||
|
||||
D:Bool = InstanceOf S0:Cls S1:Cls S2:ConstBool
|
||||
D:Bool = InstanceOf S0:Cls S1:Cls
|
||||
|
||||
Sets D based on whether S0 is a descendant of the class, interface,
|
||||
or trait in S1. (Note that this is always false for a trait). S1
|
||||
may be null at runtime if the class is not defined. The flag S2 is
|
||||
just a hint that is true if we should assume S1 might be an
|
||||
interface---the instruction must still handle it correctly if this
|
||||
hint is wrong at runtime.
|
||||
may be null at runtime if the class is not defined.
|
||||
|
||||
D:Bool = InstanceOfIface S0:Cls S1:Cls
|
||||
|
||||
Fast path for interface checks. Sets D based on whether S0 implements
|
||||
S1, but S1 must be a unique interface. This should only be used in
|
||||
repo-authoritative mode.
|
||||
|
||||
D:Bool = ExtendsClass S0:Cls S1:Cls
|
||||
|
||||
|
||||
@@ -510,6 +510,9 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ifaceofDirect(const StringData* name) const {
|
||||
return m_interfaces.lookupDefault(name, nullptr) != nullptr;
|
||||
}
|
||||
const StringData* name() const {
|
||||
return m_preClass->name();
|
||||
}
|
||||
|
||||
@@ -465,6 +465,9 @@ CALL_OPCODE(StableMapIsset)
|
||||
CALL_OPCODE(IssetElem)
|
||||
CALL_OPCODE(EmptyElem)
|
||||
|
||||
CALL_OPCODE(InstanceOf)
|
||||
CALL_OPCODE(InstanceOfIface)
|
||||
|
||||
#undef NOOP_OPCODE
|
||||
|
||||
// Thread chain of patch locations using the 4 byte space in each jmp/jcc
|
||||
@@ -1951,21 +1954,6 @@ void CodeGenerator::cgIsNTypeMem(IRInstruction* inst) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HOT_FUNC_VM static bool instanceOfHelper(const Class* objClass,
|
||||
const Class* testClass) {
|
||||
return testClass && objClass->classof(testClass);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgInstanceOf(IRInstruction* inst) {
|
||||
cgCallHelper(m_as,
|
||||
TCA(instanceOfHelper),
|
||||
inst->dst(),
|
||||
SyncOptions::kNoSyncPoint,
|
||||
ArgGroup(m_regs)
|
||||
.ssa(inst->src(0))
|
||||
.ssa(inst->src(1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check instanceof using instance bitmasks.
|
||||
*
|
||||
|
||||
@@ -57,6 +57,11 @@ bool classIsUniqueNormalClass(const Class* cls) {
|
||||
!(cls->attrs() & (AttrInterface | AttrTrait));
|
||||
}
|
||||
|
||||
bool classIsUniqueInterface(const Class* cls) {
|
||||
return classIsUnique(cls) &&
|
||||
(cls->attrs() & AttrInterface);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -2908,6 +2913,16 @@ void HhbcTranslator::emitInstanceOfD(int classNameStrId) {
|
||||
const bool isNormalClass = classIsUniqueNormalClass(maybeCls);
|
||||
const bool isUnique = classIsUnique(maybeCls);
|
||||
|
||||
/*
|
||||
* If the class is a unique interface, we can just hit the class's
|
||||
* interfaces map and call it a day.
|
||||
*/
|
||||
if (!haveBit && classIsUniqueInterface(maybeCls)) {
|
||||
push(gen(InstanceOfIface, objClass, ssaClassName));
|
||||
gen(DecRef, src);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the class is unique or a parent of the current context, we
|
||||
* don't need to load it out of target cache because it must
|
||||
@@ -2930,8 +2945,7 @@ void HhbcTranslator::emitInstanceOfD(int classNameStrId) {
|
||||
checkClass) :
|
||||
gen(InstanceOf,
|
||||
objClass,
|
||||
checkClass,
|
||||
cns(maybeCls && !isNormalClass))
|
||||
checkClass)
|
||||
);
|
||||
gen(DecRef, src);
|
||||
}
|
||||
|
||||
@@ -255,7 +255,8 @@ O(ConvObjToStr, D(Str), S(Obj), N|Er|CRc|K) \
|
||||
O(ConvCellToStr, D(Str), S(Cell), N|Er|CRc|K) \
|
||||
\
|
||||
O(ExtendsClass, D(Bool), S(Cls) C(Cls), C) \
|
||||
O(InstanceOf, D(Bool), S(Cls) S(Cls) C(Bool), C|N) \
|
||||
O(InstanceOf, D(Bool), S(Cls) S(Cls), C|N) \
|
||||
O(InstanceOfIface, D(Bool), S(Cls) CStr, C|N) \
|
||||
O(IsTypeMem, D(Bool), S(PtrToGen), NA) \
|
||||
O(IsNTypeMem, D(Bool), S(PtrToGen), NA) \
|
||||
/* name dstinfo srcinfo flags */ \
|
||||
|
||||
@@ -845,9 +845,6 @@ void LinearScan::computePreColoringHint() {
|
||||
m_preColoringHint.add(inst->src(0), 0, 1);
|
||||
}
|
||||
break;
|
||||
case InstanceOf:
|
||||
normalHint(2, 0, 0);
|
||||
break;
|
||||
case LdSSwitchDestFast:
|
||||
normalHint(1, 0, 0);
|
||||
break;
|
||||
|
||||
@@ -258,6 +258,11 @@ static CallMap s_callMap({
|
||||
{EmptyElem,{FSSA, 0}, DSSA, SSync,
|
||||
{{SSA, 1}, {VecKeyIS, 2}, {SSA, 3}}},
|
||||
|
||||
/* instanceof checks */
|
||||
{InstanceOf, (TCA)instanceOfHelper, DSSA, SNone, {{SSA, 0}, {SSA, 1}}},
|
||||
{InstanceOfIface, (TCA)Util::getMethodPtr(&Class::ifaceofDirect), DSSA,
|
||||
SNone, {{SSA, 0}, {SSA, 1}}},
|
||||
|
||||
/* debug assert helpers */
|
||||
{DbgAssertPtr, (TCA)assertTv, DNone, SNone, {{SSA, 0}}},
|
||||
});
|
||||
|
||||
@@ -326,4 +326,10 @@ RefData* staticLocInitCached(StringData* name, ActRec* fp, TypedValue val,
|
||||
return staticLocInitImpl<true>(name, fp, val, ch);
|
||||
}
|
||||
|
||||
HOT_FUNC_VM
|
||||
bool instanceOfHelper(const Class* objClass,
|
||||
const Class* testClass) {
|
||||
return testClass && objClass->classof(testClass);
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
@@ -117,6 +117,8 @@ RefData* staticLocInit(StringData* name, ActRec* fp, TypedValue val);
|
||||
RefData* staticLocInitCached(StringData* name, ActRec* fp, TypedValue val,
|
||||
TargetCache::CacheHandle ch);
|
||||
|
||||
bool instanceOfHelper(const Class* objClass, const Class* testClass);
|
||||
|
||||
} }
|
||||
|
||||
#endif
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário