예제 #1
0
/*
  The classical use/def isnt quite enough here. There are two unusual
  issues:
   - the ref/non-ref issue.
     An assignment to a var which is referenced doesnt end its
     lifetime. In fact it could just be a "use" of the var. But it
     also counts as a def.
   - the destructor issue.
     variables which might need to be destroyed later are technically
     alive, but dont interfere with any other variables in the same state.
     They /do/ interfere with any truly "live" variables, however.
     These are "dying".

   So we end up defining, use, kill, def and dying.

  use : a read of the variable, an ordinary assignment if it could
        be referenced

  kill : an unset, a ref assignment, or, for non referenced vars, any assignment

  def : ref or normal assignment

  dying : a variable whose destructor is (partially/locally) anticipated.
*/
void LiveDict::updateAccess(ExpressionPtr e) {
  int cls = e->getExprClass();
  if (cls & Expression::Store) {
    /*
      Handled when we see the lhs
    */
    return;
  }

  int eid = e->getCanonID();
  int context = e->getContext();
  bool unset = false;
  bool store = false;
  if (context & Expression::LValue && context & Expression::UnsetContext) {
    unset = true;
  } else if (context & Expression::AssignmentLHS) {
    store = true;
  }

  if (e->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
    bool use = false, kill = false, def = false;
    Symbol *sym = sv->getSymbol();
    bool isReferenced =
      e->isReferencedValid() ?
        e->isReferenced() :
        sym && sym->isReferenced();
    bool isNeeded =
      e->isNeededValid() ?
        e->isNeeded() :
        sym && sym->isNeeded();
    if (unset) {
      kill = true;
    } else if (store) {
      if (context & Expression::RefAssignmentLHS ||
          (!m_am.hasWildRefs() && !isReferenced)) {
        kill = true;
      }
      def = true;
    } else if ((context & Expression::Declaration) == Expression::Declaration) {
      // a global declaration
      def = kill = true;
    } else if (context & (Expression::LValue|
                          Expression::RefValue|
                          Expression::DeepReference|
                          Expression::UnsetContext|
                          Expression::OprLValue)) {
      use = def = true;
    } else {
      use = true;
    }
    if (kill && (!sym || isNeeded || isReferenced) &&
        !BitOps::get_bit(eid, m_altered) &&
        !BitOps::get_bit(eid, m_available)) {
      BitOps::set_bit(eid, m_dying, true);
    }
    if (use &&
        !BitOps::get_bit(eid, m_altered) &&
        !BitOps::get_bit(eid, m_available)) {
      BitOps::set_bit(eid, m_anticipated, true);
      e->setAnticipated();
    }
    if (kill) {
      BitOps::set_bit(eid, m_altered, true);
      BitOps::set_bit(eid, m_available, def);
    } else if (def) {
      BitOps::set_bit(eid, m_available, true);
    }

    if (!m_am.couldBeAliased(sv)) {
      return;
    }
  } else if (!e->is(Expression::KindOfDynamicVariable) &&
             (unset || (context & Expression::RefAssignmentLHS))) {
    // An unset, or a reference assignment to anything other
    // than a simple or dynamic variable can never affect a simple
    // variable (outside of pseudoMain).
    return;
  }

  if (store || cls & (Expression::Load|Expression::Call)) {
    bool mod =
      store ||
      (cls & Expression::Load &&
       e->getContext() & (Expression::LValue|
                          Expression::RefValue|
                          Expression::UnsetContext|
                          Expression::DeepReference|
                          Expression::OprLValue));

    ExpressionPtr cur = m_refs, prev;
    bool isLoad;
    int depth = 0, effects = 0;
    while (cur) {
      ExpressionPtr next = cur->getCanonLVal();
      int cid = cur->getCanonID();
      if (cid != eid &&
          m_am.checkAnyInterf(e, cur, isLoad, depth, effects) !=
          AliasManager::DisjointAccess) {
        if (mod) {
          BitOps::set_bit(cid, m_available, true);
        }
        if (!BitOps::get_bit(cid, m_altered) &&
            !BitOps::get_bit(cid, m_available)) {
          BitOps::set_bit(cid, m_anticipated, true);
        }
        if (!prev) {
          m_refs = next;
        } else {
          prev->setCanonPtr(next);
        }
      } else {
        prev = cur;
      }
      cur = next;
    }
  }
}
예제 #2
0
파일: ref_dict.cpp 프로젝트: Bluarggag/hhvm
void RefDict::updateAccess(ExpressionPtr e) {
  always_assert(!e->getScope()->inPseudoMain());

  int eid     = e->getCanonID();
  int context = e->getContext();

  if (first_pass) {
    if (!e->is(Expression::KindOfSimpleVariable) &&
        !e->is(Expression::KindOfDynamicVariable)) return;

    e->clearAvailable();
    e->clearReferencedValid();
    e->clearReferenced();

    SimpleVariablePtr ptr(dynamic_pointer_cast<SimpleVariable>(e));
    if (ptr && (ptr->isSuperGlobal() || ptr->isThis())) return;

    if (e->is(Expression::KindOfSimpleVariable)) {
      if (BitOps::get_bit(eid, m_referenced)) {
        e->setReferenced();
      } else if (!BitOps::get_bit(eid, m_killed)) {
        // use as a temp place holder
        e->setAvailable();
      }
    }
  }

  // let the first pass information propagate for both passes, since
  // we need it in both contexts
  if (context & Expression::RefAssignmentLHS ||
      context & Expression::RefValue ||
      context & Expression::RefParameter ||
      ((context & Expression::Declaration) == Expression::Declaration)) {
    if (e->is(Expression::KindOfSimpleVariable)) {
      BitOps::set_bit(eid, m_referenced, true);
      BitOps::set_bit(eid, m_killed, false);
    } else {
      // for dynamic variables, we must assume the worst
      BitOps::set(size(), m_referenced, -1);
      BitOps::set(size(), m_killed, 0);
    }
  } else if (e->is(Expression::KindOfSimpleVariable) &&
             context & Expression::LValue &&
             context & Expression::UnsetContext) {
    BitOps::set_bit(eid, m_referenced, false);
    BitOps::set_bit(eid, m_killed, true);
  }

  if (first_pass) return;

  // now we're on the second pass

  if (context & Expression::AssignmentLHS ||
      context & Expression::OprLValue) {
    // we dealt with this node as a store expression
    return;
  }

  int cls = e->getExprClass();

  bool isRhsNeeded = false;
  bool canKill     = false;

  ExpressionPtr lhs;
  ExpressionPtr rhs;

  if (cls & Expression::Store) {
    // we care about two cases here
    switch (e->getKindOf()) {
      case Expression::KindOfAssignmentExpression:
        // $x = ...
        {
          AssignmentExpressionPtr assign(
              static_pointer_cast<AssignmentExpression>(e));
          lhs = assign->getVariable();
          rhs = assign->getValue();
          isRhsNeeded = Expression::CheckNeededRHS(rhs);
          canKill = true;
        }
        break;
      case Expression::KindOfBinaryOpExpression:
        // $x += ...
        {
          BinaryOpExpressionPtr binop(
              static_pointer_cast<BinaryOpExpression>(e));
          if (binop->getOp() == T_PLUS_EQUAL) {
            lhs = binop->getExp1();
            rhs = binop->getExp2();
            isRhsNeeded = Expression::CheckNeededRHS(rhs);
          }
        }
        break;
      default:
        break;
    }
  }

  bool isLhsSimpleVar = false;
  bool isLhsDynamic   = false;
  bool isRefd         = false;
  if (lhs) {
    isLhsSimpleVar = lhs->is(Expression::KindOfSimpleVariable);

    // TODO: can a variable only be simple or dynamic?
    // If so, this is un-necessary
    isLhsDynamic   = lhs->is(Expression::KindOfDynamicVariable);

    if (isLhsSimpleVar) {
      // clean up the LHS AST
      lhs->clearAvailable();
      lhs->clearNeeded();
      lhs->clearNeededValid();

      if (BitOps::get_bit(lhs->getCanonID(), m_obj)) {
        lhs->setNeeded();
        lhs->setNeededValid();
      } else if (!BitOps::get_bit(lhs->getCanonID(), m_noobj)) {
        lhs->setAvailable();
      }
    }

    if (lhs->isReferencedValid() && lhs->isReferenced() && isRhsNeeded) {
      // could we possibly have modified another referenced variable?
      isRefd = true;
    }

    if (isLhsSimpleVar && isRhsNeeded) {
      // we see this case:
      // $x = new ...
      // so we mark $x as being needed
      BitOps::set_bit(lhs->getCanonID(), m_obj, true);
      BitOps::set_bit(lhs->getCanonID(), m_noobj, false);
    } else if (isLhsSimpleVar && canKill && !isRhsNeeded) {
      // we saw an assignment that was of the form
      // $x = <primitive>
      // we can now set $x to be not an object
      BitOps::set_bit(lhs->getCanonID(), m_obj, false);
      BitOps::set_bit(lhs->getCanonID(), m_noobj, true);
    }
  }

  if (isLhsDynamic && isRhsNeeded) {
    // in this case, we must set EVERY variable to contain an object
    BitOps::set(size(), m_obj, -1 /* true for each bit */);
    BitOps::set(size(), m_noobj, 0 /* false for each bit */);

    // we're done, since it can be no worse (no more conservative) than this
    return;
  }

  // do we see a load which could cause the value of this expr to be changed?
  // for example:
  // function foo(&$x) { $x = 10; }
  // $x = 30;
  // foo($x); /* <-- this is what we care about */
  if ((cls & (Expression::Load|Expression::Call)) &&
      (context & (Expression::RefValue|Expression::DeepReference))) {
    isRefd = true;
  }

  // we want to propagate this information to other simple vars we see
  if (e->is(Expression::KindOfSimpleVariable)) {
    // clean up the AST
    e->clearAvailable();
    e->clearNeeded();
    e->clearNeededValid();

    SimpleVariablePtr svp(static_pointer_cast<SimpleVariable>(e));
    if (svp->isSuperGlobal() || svp->isThis()) return;

    // update the AST to *before* the modification
    if (BitOps::get_bit(eid, m_obj)) {
      e->setNeeded();
      e->setNeededValid();
    } else if (!BitOps::get_bit(eid, m_noobj)) {
      // use as a temp place holder
      e->setAvailable();
    }

    if (context & Expression::LValue &&
        context & Expression::UnsetContext) {
      always_assert(!isRefd);
      // unset($x);
      BitOps::set_bit(eid, m_obj, false);
      BitOps::set_bit(eid, m_noobj, true);
    } else if (isRefd ||
        ((context & Expression::Declaration) == Expression::Declaration)) {
      // if a simple variable has isRefd, then we need to mark it
      // as potentially containing an object.
      // also, if the simple variable is in global context
      // then we also mark it as potentially containing an object
      BitOps::set_bit(eid, m_obj, true);
      BitOps::set_bit(eid, m_noobj, false);
    }
  }

  if (isRefd) {
    // do a scan for every simple variable referenced value
    // in the dictionary and mark it as potentially
    // containing an object (in the bit vector)
    for (int i = size(); i--; ) {
      if (ExpressionPtr e = get(i)) {
        always_assert(e->is(Expression::KindOfSimpleVariable));
        always_assert(((unsigned int)i) == e->getCanonID());
        if (BitOps::get_bit(i, m_referenced)) {
          BitOps::set_bit(i, m_obj, true);
          BitOps::set_bit(i, m_noobj, false);
        }
      }
    }
  }
}