diff --git a/hphp/runtime/vm/translator/hopt/codegen.cpp b/hphp/runtime/vm/translator/hopt/codegen.cpp index d83ea4473..1c77505bb 100644 --- a/hphp/runtime/vm/translator/hopt/codegen.cpp +++ b/hphp/runtime/vm/translator/hopt/codegen.cpp @@ -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); } diff --git a/hphp/runtime/vm/translator/hopt/simplifier.cpp b/hphp/runtime/vm/translator/hopt/simplifier.cpp index 00575e7aa..4c0bf389b 100644 --- a/hphp/runtime/vm/translator/hopt/simplifier.cpp +++ b/hphp/runtime/vm/translator/hopt/simplifier.cpp @@ -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; }