Implement IsObject in IR
It turns out is_object actually shouldn't be calling isResource, so this really wasn't as bad as everyone thought. I cleaned up the simplifier logic for this instruction (even though is_object is weird, we can still optimize it away when the src isn't even KindOfObject). A more elegant solution might be to introduce Type::Resource, but that would be more complex and I just want to get something working for the purposes of lockdown.
Esse commit está contido em:
@@ -1596,20 +1596,44 @@ void CodeGenerator::emitSetCc(IRInstruction* inst, ConditionCode cc) {
|
||||
}
|
||||
|
||||
ConditionCode CodeGenerator::emitIsTypeTest(IRInstruction* inst, bool negate) {
|
||||
if (inst->getTypeParam().subtypeOf(Type::Obj)) {
|
||||
// Task #2094715: Handle isType tests for Type::Obj, which
|
||||
// requires checking that checked object is not a resource
|
||||
CG_PUNT(cgIsTypeObject);
|
||||
auto const src = inst->getSrc(0);
|
||||
|
||||
if (inst->getTypeParam().equals(Type::Obj)) {
|
||||
auto const srcReg = m_regs[src].getReg();
|
||||
if (src->isA(Type::PtrToGen)) {
|
||||
emitTestTVType(m_as, KindOfObject, srcReg[TVOFF(m_type)]);
|
||||
TCA toPatch = m_as.code.frontier;
|
||||
m_as. jne8(toPatch); // 1
|
||||
|
||||
// Get the ObjectData*
|
||||
emitDeref(m_as, srcReg, rScratch);
|
||||
m_as. cmpq(SystemLib::s_resourceClass,
|
||||
rScratch[ObjectData::getVMClassOffset()]);
|
||||
// 1:
|
||||
m_as.patchJcc8(toPatch, m_as.code.frontier);
|
||||
} else {
|
||||
// Cases where src isn't an Obj should have been simplified away
|
||||
if (!src->isA(Type::Obj)) {
|
||||
CG_PUNT(IsType-KnownWrongType);
|
||||
}
|
||||
m_as. cmpq(SystemLib::s_resourceClass,
|
||||
srcReg[ObjectData::getVMClassOffset()]);
|
||||
}
|
||||
// At this point, the flags say "equal" if is_object is false.
|
||||
return negate ? CC_E : CC_NE;
|
||||
}
|
||||
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
if (src->isA(Type::PtrToGen)) {
|
||||
PhysReg base = m_regs[src].getReg();
|
||||
return emitTypeTest(inst, base[TVOFF(m_type)], negate);
|
||||
}
|
||||
assert(src->isA(Type::Gen));
|
||||
assert(!src->isConst());
|
||||
|
||||
PhysReg srcReg = m_regs[src].getReg(1); // type register
|
||||
if (srcReg == InvalidReg) {
|
||||
CG_PUNT(IsType-KnownType);
|
||||
}
|
||||
return emitTypeTest(inst, srcReg, negate);
|
||||
}
|
||||
|
||||
|
||||
@@ -1178,20 +1178,26 @@ SSATmp* Simplifier::simplifyIsType(IRInstruction* inst) {
|
||||
// The comparisons below won't work for these cases covered by this
|
||||
// assert, and we currently don't generate these types.
|
||||
assert(type.isKnownUnboxedDataType() && type != Type::StaticStr);
|
||||
if (type != Type::Obj) {
|
||||
if (srcType.subtypeOf(type) || (type.isString() && srcType.isString())) {
|
||||
return cns(trueSense);
|
||||
}
|
||||
if (srcType != Type::Cell) {
|
||||
return cns(!trueSense);
|
||||
}
|
||||
|
||||
// CountedStr and StaticStr are disjoint, but compatible for this purpose.
|
||||
if (type.isString() && srcType.isString()) {
|
||||
return cns(trueSense);
|
||||
}
|
||||
if (srcType != Type::Obj) {
|
||||
// Note: for IsObject*, we need to emit a call to ObjectData::isResource
|
||||
// (or equivalent), so we can't fold away the case where we know we are
|
||||
// checking an object.
|
||||
|
||||
// The types are disjoint; the result must be false.
|
||||
if ((srcType & type).equals(Type::Bottom)) {
|
||||
return cns(!trueSense);
|
||||
}
|
||||
|
||||
// The src type is a subtype of the tested type. You'd think the result would
|
||||
// always be true, but it's not for is_object.
|
||||
if (!type.subtypeOf(Type::Obj) && srcType.subtypeOf(type)) {
|
||||
return cns(trueSense);
|
||||
}
|
||||
|
||||
// At this point, either the tested type is a subtype of the src type, or they
|
||||
// are non-disjoint but neither is a subtype of the other. (Or it's the weird
|
||||
// Obj case.) We can't simplify this away.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário