in hphp/hhbbc/optimize.cpp [216:311]
bool hasObviousStackOutput(const Bytecode& op, const Interp& interp) {
switch (op.op) {
case Op::Null:
case Op::NullUninit:
case Op::True:
case Op::False:
case Op::Int:
case Op::Double:
case Op::String:
case Op::LazyClass:
case Op::Dict:
case Op::Vec:
case Op::Keyset:
case Op::NewDictArray:
case Op::NewStructDict:
case Op::NewVec:
case Op::NewKeysetArray:
case Op::AddNewElemC:
case Op::NewCol:
case Op::NewPair:
case Op::ClassName:
case Op::LazyClassFromClass:
case Op::File:
case Op::Dir:
case Op::Concat:
case Op::ConcatN:
case Op::Not:
case Op::Same:
case Op::NSame:
case Op::Eq:
case Op::Neq:
case Op::Lt:
case Op::Gt:
case Op::Lte:
case Op::Gte:
case Op::Cmp:
case Op::Shl:
case Op::Shr:
case Op::CastBool:
case Op::CastInt:
case Op::CastDouble:
case Op::CastString:
case Op::CastDict:
case Op::CastVec:
case Op::CastKeyset:
case Op::DblAsBits:
case Op::InstanceOfD:
case Op::IsLateBoundCls:
case Op::IsTypeStructC:
case Op::CombineAndResolveTypeStruct:
case Op::RecordReifiedGeneric:
case Op::InstanceOf:
case Op::Print:
case Op::Exit:
case Op::AKExists:
case Op::IssetL:
case Op::IsUnsetL:
case Op::IssetG:
case Op::IssetS:
case Op::IsTypeC:
case Op::IsTypeL:
case Op::OODeclExists:
return true;
case Op::This:
case Op::BareThis:
if (auto tt = thisType(interp.index, interp.ctx)) {
auto t = interp.state.stack.back().type;
if (t.couldBe(BInitNull) && !t.subtypeOf(BInitNull)) {
t = unopt(std::move(t));
}
return !t.strictSubtypeOf(*tt);
}
return true;
case Op::CGetL:
case Op::CGetQuietL:
case Op::CUGetL:
case Op::CGetL2:
case Op::PushL:
return true;
// The output of SetL is obvious if you know what its input is
// (which we'll assert if we know).
case Op::SetL:
return true;
// The output of SetM isn't quite as obvious as SetL, but the jit
// can work it out from the input just as well as hhbbc (if not better).
case Op::SetM:
return true;
default:
return false;
}
}