Beispiel #1
0
folly::Optional<AliasClass> AliasClass::precise_union(AliasClass o) const {
  if (o <= *this) return *this;
  if (*this <= o) return o;

  auto const unioned = static_cast<rep>(m_bits | o.m_bits);

  // For a precise union, we need to make sure the returned class is not any
  // bigger than it should be.  This means we can't deal with situations where
  // we have disjoint stags, and right now we also don't try to deal with
  // situations that have the same stag in a combinable way.  (E.g. two
  // adjacent AStack ranges.)
  auto const stag1 = m_stag;
  auto const stag2 = o.m_stag;
  if (stag1 == STag::None && stag2 == STag::None) {
    return AliasClass{unioned};
  }
  if (stag1 == STag::None && stag2 != STag::None) {
    return o.precise_union(*this); // flip args
  }
  assertx(stag1 != STag::None);
  if (stag2 != STag::None)       return folly::none;
  if (o.m_bits & stagBit(stag1)) return folly::none;

  // Keep the data and stag from this, but change its bits.
  auto ret = *this;
  ret.m_bits = unioned;
  assertx(ret.m_stag == stag1);
  return ret;
}
Beispiel #2
0
bool AliasClass::operator<=(AliasClass o) const {
  if (m_bits == BEmpty) return true;

  auto const isect = static_cast<rep>(m_bits & o.m_bits);
  if (isect != m_bits) return false;

  // If they have the same specialized tag, then since isect is equal to
  // m_bits, the stagBit must be part of the intersection or be BEmpty.  This
  // means they can only be in a subclass relationship if that specialized data
  // is.
  if (m_stag == o.m_stag) return subclassData(o);

  /*
   * Disjoint stags.  The stagBit for m_stag must be part of the intersection
   * (or be BEmpty), since isect == m_bits above.  This breaks down into the
   * following cases:
   *
   * If the osbit is part of the intersection, then this can't be a subclass of
   * `o', because this has only generic information for that bit but it is set
   * in isect.  If the osbit is BEmpty, osbit & isect is zero, which avoids
   * this case.
   *
   * The remaining situations are that m_stag is STag::None, in which case it
   * is a subclass since osbit wasn't in the intersection.  Or that m_stag has
   * a bit that is in the isect (since m_bits == isect), and that bit is set in
   * o.m_bits.  In either case this is a subclass, so we can just return true.
   */
  auto const osbit = stagBit(o.m_stag);
  if (osbit & isect) return false;
  return true;
}
Beispiel #3
0
bool AliasClass::checkInvariants() const {
  switch (m_stag) {
  case STag::None:    break;
  case STag::Frame:   break;
  case STag::Prop:    break;
  case STag::ElemI:   break;
  case STag::Stack:
    assertx(m_stack.base->type() <= TStkPtr ||
           m_stack.base->type() <= TFramePtr);
    assertx(m_stack.size != 0);  // use AEmpty if you want that
    assertx(m_stack.size > 0);
    break;
  case STag::ElemS:
    assertx(m_elemS.key->isStatic());
    break;
  case STag::MIState:
    break;
  case STag::Ref:
    assertx(m_ref.boxed->isA(TBoxedCell));
    break;
  }

  assertx(m_bits & stagBit(m_stag));

  return true;
}
Beispiel #4
0
AliasClass AliasClass::operator|(AliasClass o) const {
  if (auto const c = precise_union(o)) return *c;

  auto const unioned = static_cast<rep>(m_bits | o.m_bits);

  // If they have the same stag, try to merge them with unionData.
  auto stag1 = m_stag;
  auto stag2 = o.m_stag;
  if (stag1 == stag2) return unionData(unioned, *this, o);

  // If one of the alias classes have a non-None stag, we can only keep it if
  // the other doesn't have the corresponding bit set.
  if (stag1 != STag::None && (o.m_bits & stagBit(stag1))) stag1 = STag::None;
  if (stag2 != STag::None && (m_bits & stagBit(stag2))) stag2 = STag::None;

  auto ret = AliasClass{unioned};
  if (stag1 == stag2) return ret;       // both None.

  // Note: union operations are guaranteed to be commutative, so if there are
  // two non-None stags, we have to consistently choose between them. For now
  // we keep the one with a smaller `rep' value, instead of discarding both.
  const AliasClass* chosen = &o;
  auto stag = stag2;
  if (stag1 != STag::None) {
    if (stag2 == STag::None || stagBit(stag1) < stagBit(stag2)) {
      chosen = this;
      stag = stag1;
    }
  }

  switch (stag) {
  case STag::None:
    break;
  case STag::Frame:   new (&ret.m_frame) AFrame(chosen->m_frame); break;
  case STag::Prop:    new (&ret.m_prop) AProp(chosen->m_prop); break;
  case STag::ElemI:   new (&ret.m_elemI) AElemI(chosen->m_elemI); break;
  case STag::ElemS:   new (&ret.m_elemS) AElemS(chosen->m_elemS); break;
  case STag::Stack:   new (&ret.m_stack) AStack(chosen->m_stack); break;
  case STag::MIState: new (&ret.m_mis) AMIState(chosen->m_mis); break;
  case STag::Ref:     new (&ret.m_ref) ARef(chosen->m_ref); break;
  }
  ret.m_stag = stag;
  return ret;
}
Beispiel #5
0
/*
 * TODO(#2884927): we probably need to be aware of possibly-integer-like string
 * keys here before we can start using ElemS for anything.  (Or else ensure
 * that we never use ElemS with an integer-like string.)
 */
bool AliasClass::maybe(AliasClass o) const {
  auto const isect = static_cast<rep>(m_bits & o.m_bits);
  if (isect == 0) return false;
  if (*this <= o || o <= *this) return true;

  /*
   * If we have the same stag, then the cases are either the stag is in the
   * intersection or not.  If it's not (including if it was BEmpty), we already
   * know the intersection is non-empty and return true.
   *
   * If it is in the intersection, and it is not the only relevant bit, then we
   * still have a non-empty intersection.
   *
   * Finally if it's in the intersection and the only isect bit, then we need
   * to see if the data is in a maybe relationship.
   */
  if (m_stag == o.m_stag) {
    auto const bit = stagBit(m_stag);
    assertx(isect != 0);
    if ((bit & isect) == isect) return maybeData(o);
    return true;
  }

  /*
   * The stags are different.  However, since isect is non-empty, there are
   * three cases:
   *
   *    o One of the stag bits is not in the intersection, and thus not
   *      relevant.  Since the other stag bit is in the intersection, but
   *      didn't have specialized information from one of the intersectees, the
   *      intersection is non-empty and we should return true.
   *
   *    o Both of the stag bits are not in the intersection, and thus not
   *      relevant.  Some other bit was set, since we already checked that
   *      isect was non-zero, so we should return true.
   *
   *    o Both of the stag bits are in the intersection.  But each intersectee
   *      therefore had only generic information for the bit of the other, so
   *      the intersection is non-empty, and we should return true.
   *
   * All of these cases are handled by the following statement:
   */
  return true;
}
Beispiel #6
0
bool AliasClass::checkInvariants() const {
  switch (m_stag) {
  case STag::None:    break;
  case STag::Frame:   break;
  case STag::Prop:    break;
  case STag::ElemI:   break;
  case STag::Stack:
    assertx(m_stack.size > 0);
    break;
  case STag::ElemS:
    assertx(m_elemS.key->isStatic());
    break;
  case STag::MIState:
    break;
  case STag::Ref:
    assertx(m_ref.boxed->isA(TBoxedCell));
    break;
  }

  assertx(m_bits & stagBit(m_stag));

  return true;
}
Beispiel #7
0
AliasClass AliasClass::operator|(AliasClass o) const {
  if (o <= *this) return *this;
  if (*this <= o) return o;

  auto const unioned = static_cast<rep>(m_bits | o.m_bits);

  // Note: union operations are guaranteed to be commutative, so if there are
  // two non-None stags, we have to consistently choose between them.  For now
  // we throw both away in any case where they differ, and try to merge them
  // with unionData if they are the same.  If only one had an stag, we can keep
  // it only if the other didn't have that bit set.
  auto const stag1 = m_stag;
  auto const stag2 = o.m_stag;
  if (stag1 == stag2) return unionData(unioned, *this, o);
  if (stag1 != STag::None && stag2 != STag::None) {
    return AliasClass{unioned};
  }
  if (stag2 != STag::None) return o | *this;
  if (o.m_bits & stagBit(stag1)) {
    return AliasClass{unioned};
  }

  auto ret = AliasClass{unioned};
  switch (stag1) {
  case STag::None:
    break;
  case STag::Frame:   new (&ret.m_frame) AFrame(m_frame); break;
  case STag::Prop:    new (&ret.m_prop) AProp(m_prop); break;
  case STag::ElemI:   new (&ret.m_elemI) AElemI(m_elemI); break;
  case STag::ElemS:   new (&ret.m_elemS) AElemS(m_elemS); break;
  case STag::Stack:   new (&ret.m_stack) AStack(m_stack); break;
  case STag::MIState: new (&ret.m_mis) AMIState(m_mis); break;
  }
  ret.m_stag = stag1;
  return ret;
}