Ejemplo n.º 1
0
bool Type::checkValid() const {
  static_assert(sizeof(m_arrayKind) == 1,
                "Type expects ArrayKind to be one byte");
  if (m_extra) {
    assert((!(m_bits & kAnyObj) || !(m_bits & kAnyArr)) &&
           "Conflicting specialization");

    if (canSpecializeArrayKind() && hasArrayKind() && !m_hasConstVal) {
      assert(!(m_extra & 0xffffffffffff0000) &&
             "Non-zero padding bits in Type with array kind");
    }
  }

  return true;
}
Ejemplo n.º 2
0
Type Type::operator-(Type other) const {
  auto const newBits = m_bits & ~other.m_bits;
  auto const spec1 = isSpecialized();
  auto const spec2 = other.isSpecialized();

  // The common easy case is when neither type is specialized.
  if (LIKELY(!spec1 && !spec2)) return Type(newBits);

  if (spec1 && spec2) {
    if (canSpecializeClass() != other.canSpecializeClass()) {
      // Both are specialized but in different ways. Our specialization is
      // preserved.
      return Type(newBits, m_extra);
    }

    // Subtracting different specializations of the same type could get messy
    // so we don't support it for now.
    always_assert(specializedType() == other.specializedType() &&
                  "Incompatible specialized types given to operator-");

    // If we got here, both types have the same specialization, so it's removed
    // from the result.
    return Type(newBits);
  }

  // If masking out other's bits removed all of the bits that correspond to our
  // specialization, take it out. Otherwise, preserve it.
  if (spec1) {
    if (canSpecializeClass()) {
      if (!(newBits & kAnyObj)) return Type(newBits);
      return Type(newBits, m_class);
    }
    if (canSpecializeArrayKind()) {
      if (!(newBits & kAnyArr)) return Type(newBits);
      return Type(newBits, m_arrayKind);
    }
    not_reached();
  }

  // Only other is specialized. This is where things get a little fuzzy. We
  // want to be able to support things like Obj - Obj<C> but we can't represent
  // Obj<~C>. We compromise and return Bottom in cases like this, which means
  // we need to be careful because (a - b) == Bottom doesn't imply a <= b in
  // this world.
  if (other.canSpecializeClass()) return Type(newBits & ~kAnyObj);
  return Type(newBits & ~kAnyArr);
}
Ejemplo n.º 3
0
Type Type::combine(bits_t newBits, Type other) const {
  static_assert(std::is_same<Oper, Union>::value ||
                std::is_same<Oper, Intersect>::value,
                "Type::combine given unsupported template argument");

  // If neither type is specialized, the result is simple.
  if (LIKELY(!isSpecialized() && !other.isSpecialized())) {
    return Type(newBits);
  }

  // If one of the types can't be specialized while the other is specialized,
  // preserve the specialization.
  if (!canSpecializeAny() || !other.canSpecializeAny()) {
    auto const specType = isSpecialized() ? specializedType()
                                          : other.specializedType();

    // If the specialized type doesn't exist in newBits, drop the
    // specialization.
    if (newBits & specType.m_bits) return Type(newBits, specType.m_extra);
    return Type(newBits);
  }

  // If both types are eligible for the same kind of specialization and at
  // least one is specialized, delegate to Oper::combineSame.
  if (canSpecializeClass() && other.canSpecializeClass()) {
    folly::Optional<const Class*> aClass, bClass;
    if (getClass()) aClass = getClass();
    if (other.getClass()) bClass = other.getClass();

    return Oper::template combineSame<ClassOps>(newBits, kAnyObj,
                                                aClass, bClass);
  }

  if (canSpecializeArrayKind() && other.canSpecializeArrayKind()) {
    folly::Optional<ArrayData::ArrayKind> aKind, bKind;
    if (hasArrayKind()) aKind = getArrayKind();
    if (other.hasArrayKind()) bKind = other.getArrayKind();

    return Oper::template combineSame<ArrayOps>(newBits, kAnyArr, aKind, bKind);
  }

  // The types are eligible for different kinds of specialization and at least
  // one is specialized, so delegate to Oper::combineDifferent.
  return Oper::combineDifferent(newBits, *this, other);
}
Ejemplo n.º 4
0
Type Type::operator-(Type other) const {
  auto const newBits = m_bits & ~other.m_bits;

  if (m_hasConstVal) {
    // If other is a constant of the same type, the result is Bottom or this
    // depending on whether or not it's the same constant.
    if (other.m_bits == m_bits && other.m_hasConstVal) {
      return other.m_extra == m_extra ? Bottom : *this;
    }

    // Otherwise, just check to see if the constant's type was removed in
    // newBits.
    return (newBits & m_bits) ? *this : Bottom;
  }

  // Rather than try to represent types like "all Ints except 24", treat t -
  // Int<24> as t - Int.
  other = other.dropConstVal();

  auto const spec1 = isSpecialized();
  auto const spec2 = other.isSpecialized();

  // The common easy case is when neither type is specialized.
  if (LIKELY(!spec1 && !spec2)) return Type(newBits);

  if (spec1 && spec2) {
    if (canSpecializeClass() != other.canSpecializeClass()) {
      // Both are specialized but in different ways. Our specialization is
      // preserved.
      return Type(newBits, m_extra);
    }

    // Subtracting different specializations of the same type could get messy
    // so we don't support it for now.
    always_assert(specializedType() == other.specializedType() &&
                  "Incompatible specialized types given to operator-");

    // If we got here, both types have the same specialization, so it's removed
    // from the result.
    return Type(newBits);
  }

  // If masking out other's bits removed all of the bits that correspond to our
  // specialization, take it out. Otherwise, preserve it.
  if (spec1) {
    if (canSpecializeClass()) {
      if (!(newBits & kAnyObj)) return Type(newBits);
      return Type(newBits, m_class);
    }
    if (canSpecializeArrayKind()) {
      if (!(newBits & kAnyArr)) return Type(newBits);
      return Type(newBits, getArrayKind());
    }
    not_reached();
  }

  // Only other is specialized. This is where things get a little fuzzy. We
  // want to be able to support things like Obj - Obj<C> but we can't represent
  // Obj<~C>. We compromise and return Bottom in cases like this, which means
  // we need to be careful because (a - b) == Bottom doesn't imply a <= b in
  // this world.
  if (other.canSpecializeClass()) return Type(newBits & ~kAnyObj);
  return Type(newBits & ~kAnyArr);
}