Type Type::relaxToGuardable() const { auto const ty = unspecialize(); if (ty.isKnownDataType()) return ty; if (ty.subtypeOf(UncountedInit)) return Type::UncountedInit; if (ty.subtypeOf(Uncounted)) return Type::Uncounted; if (ty.subtypeOf(Cell)) return Type::Cell; if (ty.subtypeOf(BoxedCell)) return Type::BoxedCell; if (ty.subtypeOf(Gen)) return Type::Gen; not_reached(); }
void cgCheckType(IRLS& env, const IRInstruction* inst) { // Note: If you add new supported type checks, you should update // negativeCheckType() to indicate whether it is precise or not. auto const src = inst->src(0); auto const dst = inst->dst(); auto const srcData = srcLoc(env, inst, 0).reg(0); auto const srcType = srcLoc(env, inst, 0).reg(1); auto& v = vmain(env); auto const doJcc = [&] (ConditionCode cc, Vreg sf) { fwdJcc(v, env, ccNegate(cc), sf, inst->taken()); }; auto const doMov = [&] { auto const dstData = dstLoc(env, inst, 0).reg(0); auto const dstType = dstLoc(env, inst, 0).reg(1); if (dst->isA(TBool) && !src->isA(TBool)) { v << movtqb{srcData, dstData}; } else { v << copy{srcData, dstData}; } if (dstType == InvalidReg) return; if (srcType != InvalidReg) { v << copy{srcType, dstType}; } else { v << ldimmq{src->type().toDataType(), dstType}; } }; auto const typeParam = inst->typeParam(); if (src->isA(typeParam)) { // src is the target type or better. Just define our dst. doMov(); return; } if (!src->type().maybe(typeParam)) { // src is definitely not the target type. Always jump. v << jmp{label(env, inst->taken())}; return; } if (srcType != InvalidReg) { emitTypeTest(v, env, typeParam, srcType, srcData, v.makeReg(), doJcc); doMov(); return; } if (src->type() <= TBoxedCell && typeParam <= TBoxedCell) { // We should never have specific known Boxed types; those should only be // used for hints and predictions. always_assert(!(typeParam < TBoxedInitCell)); doMov(); return; } /* * See if we're just checking the array kind or object class of a value with * a mostly-known type. * * Important: We don't support typeParam being something like * StaticArr=kPackedKind unless the src->type() also already knows its * staticness. We do allow things like CheckType<Arr=Packed> t1:StaticArr, * though. This is why we have to check that the unspecialized type is at * least as big as the src->type(). */ if (typeParam.isSpecialized() && typeParam.unspecialize() >= src->type()) { detail::emitSpecializedTypeTest(v, env, typeParam, srcData, v.makeReg(), doJcc); doMov(); return; } /* * Since not all of our unions carry a type register, there are some * situations with strings and arrays that are neither constantly-foldable * nor in the emitTypeTest() code path. * * We currently actually check their persistent bit here, which will let * both static and uncounted strings through. Also note that * CheckType<Uncounted> t1:{Null|Str} doesn't get this treatment currently--- * the emitTypeTest() path above will only check the type register. */ if (!typeParam.isSpecialized() && typeParam <= TUncounted && src->type().subtypeOfAny(TStr, TArr) && src->type().maybe(typeParam)) { assertx(src->type().maybe(TPersistent)); auto const sf = v.makeReg(); v << cmplim{0, srcData[FAST_REFCOUNT_OFFSET], sf}; doJcc(CC_L, sf); doMov(); return; } always_assert_flog( false, "Bad src: {} and dst: {} types in '{}'", src->type(), typeParam, *inst ); }