Пример #1
0
ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
  switch (e->getKindOf()) {
  case Expression::KindOfQOpExpression:
    canonicalizeKid(e, e->getNthExpr(0), 0);
    beginScope();
    canonicalizeKid(e, e->getNthExpr(1), 1);
    resetScope();
    canonicalizeKid(e, e->getNthExpr(2), 2);
    endScope();
    return canonicalizeNode(e);

  case Expression::KindOfBinaryOpExpression:
    if (spc(BinaryOpExpression,e)->isShortCircuitOperator()) {
      canonicalizeKid(e, e->getNthExpr(0), 0);
      beginScope();
      canonicalizeKid(e, e->getNthExpr(1), 1);
      endScope();
      return canonicalizeNode(e);
    }
    break;

  default:
    break;
  }

  for (int i = 0, n = e->getKidCount(); i < n; i++) {
    canonicalizeKid(e, e->getNthExpr(i), i);
  }

  return canonicalizeNode(e);
}
Пример #2
0
/**
 * Rewrites the expression rooted in ep so that it is in a form
 * that a query processor can evaluate while referencing only
 * state that is contained in the query processor or supplied
 * to the query processor in the form of arguments to the query.
 * For instance, a reference to a local variable in the scope
 * containing the query expression will be rewritten into a
 * reference to a (synthetic) parameter of the query expression.
 * This is similar to the way lambda expressions capture variables
 * from their enclosing environment.
 * Note that rewriting implies allocating new objects.
 * The original construct is not mutated in any way.
 * If the original construct is already in the right form, it is
 * returned as is.
 */
ExpressionPtr CaptureExtractor::rewrite(ExpressionPtr ep) {
  assert(ep != nullptr);
  switch (ep->getKindOf()) {
    case Expression::KindOfQueryExpression: {
      return rewriteQuery(static_pointer_cast<QueryExpression>(ep));
    }
    case Expression::KindOfSelectClause: {
      // leave select clauses alone, another visitor deals with them.
      return ep;
    }
    case Expression::KindOfFromClause:
    case Expression::KindOfLetClause:
    case Expression::KindOfIntoClause:
    case Expression::KindOfWhereClause: {
      return rewriteSimpleClause(static_pointer_cast<SimpleQueryClause>(ep));
    }
    case Expression::KindOfGroupClause:
    case Expression::KindOfJoinClause:
    case Expression::KindOfOrderbyClause:
    case Expression::KindOfOrdering: {
      // leave these alone. they are query specific and not parameterizable.
      return ep;
    }
    case Expression::KindOfObjectPropertyExpression: {
      return rewriteObjectProperty(
        static_pointer_cast<ObjectPropertyExpression>(ep));
    }
    case Expression::KindOfSimpleFunctionCall: {
      return rewriteCall(static_pointer_cast<SimpleFunctionCall>(ep));
    }
    case Expression::KindOfScalarExpression: {
      // Leave scalars alone. If the query processor can't handle them
      // rewriting won't help.
      return ep;
    }
    case Expression::KindOfUnaryOpExpression: {
      return rewriteUnary(static_pointer_cast<UnaryOpExpression>(ep));
    }
    case Expression::KindOfBinaryOpExpression: {
      return rewriteBinary(static_pointer_cast<BinaryOpExpression>(ep));
    }
    case Expression::KindOfSimpleVariable: {
      return rewriteSimpleVariable(static_pointer_cast<SimpleVariable>(ep));
    }
    case Expression::KindOfExpressionList: {
      return rewriteExpressionList(static_pointer_cast<ExpressionList>(ep));
    }
    default: {
      // If we get here, the expression is not a candidate for evaluation
      // by the query processor, so just turn it into a query parameter.
      return newQueryParamRef(ep);
    }
  }
}
Пример #3
0
/*
  Determine whether the rhs behaves normall, or abnormally.

  1) If the expression is the silence operator, recurse on the inner expression.
  2) If the expression is a list assignment expression, recurse on the
     RHS of the expression.
  3) If the expression is one of the following, then E behaves normally:
  Simple/Dynamic variable (including $this and superglobals)
  Array element expression
  Property expression
  Static variable expression
  Function call expression
  Preinc/predec expression (but not postinc/postdec)
  Assignment expression
  Assignment op expression
  Binding assignment expression
  Include/require expression
  Eval expression
  Array expression
  Array cast expression
  4) For all other expressions, E behaves abnormally. This includes:
  All binary operator expressions
  All unary operator expressions except silence and preinc/predec
  Scalar expression of type null, bool, int, double, or string
  Qop expression (?:)
  Constant expression
  Class constant expression
  Isset or empty expression
  Exit expression
  Instanceof expression
*/
static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
  switch (rhs->getKindOf()) {
    case Expression::KindOfSimpleVariable:
    case Expression::KindOfDynamicVariable:
    case Expression::KindOfArrayElementExpression:
    case Expression::KindOfObjectPropertyExpression:
    case Expression::KindOfStaticMemberExpression:
    case Expression::KindOfSimpleFunctionCall:
    case Expression::KindOfDynamicFunctionCall:
    case Expression::KindOfObjectMethodExpression:
    case Expression::KindOfNewObjectExpression:
    case Expression::KindOfAssignmentExpression:
    case Expression::KindOfIncludeExpression:
      return ListAssignment::Regular;

    case Expression::KindOfListAssignment:
      return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());

    case Expression::KindOfUnaryOpExpression: {
      UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(rhs));
      switch (u->getOp()) {
        case '@':
          return GetRHSKind(u->getExpression());
        case T_INC:
        case T_DEC:
          return u->getFront() ?
            ListAssignment::Regular : ListAssignment::Checked;
        case T_EVAL:
        case T_ARRAY:
        case T_ARRAY_CAST:
          return ListAssignment::Regular;
        default:
          return ListAssignment::Null;
      }
      break;
    }

    case Expression::KindOfBinaryOpExpression: {
      BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(rhs));
      return b->isAssignmentOp() || b->getOp() == '+' ?
        ListAssignment::Regular : ListAssignment::Null;
    }
    case Expression::KindOfQOpExpression:
      return ListAssignment::Checked;

    default: break;
  }
  return ListAssignment::Null;
}
Пример #4
0
static bool isReadOnlyAccess(ExpressionPtr e) {
  if (e->getContext() & (Expression::UnsetContext|
                         Expression::RefValue|
                         Expression::LValue)) {
    return false;
  }
  switch (e->getKindOf()) {
  case Expression::KindOfConstantExpression:
  case Expression::KindOfSimpleVariable:
  case Expression::KindOfArrayElementExpression:
  case Expression::KindOfDynamicVariable:
    return true;
  default:
    return false;
  }
}
Пример #5
0
/**
 * Traverses the expression tree rooted at e and returns true if
 * any node in the tree is a simple variable that references a
 * name in m_boundVars.
 */
bool CaptureExtractor::dependsOnQueryOnlyState(ExpressionPtr e) {
  assert(e != nullptr);
  if (e->getKindOf() == Expression::KindOfSimpleVariable) {
    auto sv = static_pointer_cast<SimpleVariable>(e);
    auto varName = sv->getName();
    for (auto &boundVar : m_boundVars) {
      if (varName == boundVar) return true;
    }
    return false;
  }
  auto numKids = e->getKidCount();
  for (int i = 0; i < numKids; i++) {
    auto ei = e->getNthExpr(i);
    if (ei == nullptr) return false; //Default param
    if (dependsOnQueryOnlyState(ei)) return true;
  }
  return false;
}
Пример #6
0
void DataFlowWalker::process(ExpressionPtr e, bool doAccessChains) {
  if ((e->getContext() & (Expression::AssignmentLHS|Expression::OprLValue)) ||
      (!doAccessChains && e->hasContext(Expression::AccessContext))) {
    return;
  }

  switch (e->getKindOf()) {
    case Expression::KindOfListAssignment:
      processAccessChainLA(static_pointer_cast<ListAssignment>(e));
      processAccess(e);
      break;
    case Expression::KindOfArrayElementExpression:
    case Expression::KindOfObjectPropertyExpression:
      if (!e->hasContext(Expression::AccessContext)) {
        processAccessChain(e);
      }
      // fall through
    case Expression::KindOfObjectMethodExpression:
    case Expression::KindOfDynamicFunctionCall:
    case Expression::KindOfSimpleFunctionCall:
    case Expression::KindOfNewObjectExpression:
    case Expression::KindOfIncludeExpression:
    case Expression::KindOfSimpleVariable:
    case Expression::KindOfDynamicVariable:
    case Expression::KindOfStaticMemberExpression:
    case Expression::KindOfConstantExpression:
      processAccess(e);
      break;
    case Expression::KindOfAssignmentExpression:
    case Expression::KindOfBinaryOpExpression:
    case Expression::KindOfUnaryOpExpression: {
      ExpressionPtr var = e->getStoreVariable();
      if (var && var->getContext() & (Expression::AssignmentLHS|
                                      Expression::OprLValue)) {
        processAccessChain(var);
        processAccess(var);
      }
      // fall through
    }
    default:
      processAccess(e);
      break;
  }
}
Пример #7
0
static inline std::string ExtractDocComment(ExpressionPtr e) {
  if (!e) return "";
  switch (e->getKindOf()) {
  case Expression::KindOfAssignmentExpression: {
    AssignmentExpressionPtr ae(static_pointer_cast<AssignmentExpression>(e));
    return ExtractDocComment(ae->getVariable());
  }
  case Expression::KindOfSimpleVariable: {
    SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
    return sv->getDocComment();
  }
  case Expression::KindOfConstantExpression: {
    ConstantExpressionPtr ce(static_pointer_cast<ConstantExpression>(e));
    return ce->getDocComment();
  }
  default: return "";
  }
  return "";
}
Пример #8
0
static inline
std::string ExtractInitializer(AnalysisResultPtr ar, ExpressionPtr e) {
  switch (e->getKindOf()) {
  case Expression::KindOfParameterExpression:
    {
      auto p = static_pointer_cast<ParameterExpression>(e);
      if (!p->defaultValue()) return "";
      return p->defaultValue()->getText(ar);
    }
  default:
    // TODO(stephentu): this doesn't allow us to tell the difference between
    // something like:
    //   class X { public $x;        } versus
    //   class X { public $x = null; }
    // we'll just end up treating both cases like the latter
    return e->getText(ar);
  }
  return "";
}
Пример #9
0
static ExpressionPtr cloneForInlineRecur(InlineCloneInfo &info,
                                         ExpressionPtr exp,
                                         const std::string &prefix,
                                         AnalysisResultConstPtr ar,
                                         FunctionScopePtr scope) {
  exp->getOriginalScope(); // make sure to cache the original scope
  exp->setBlockScope(scope);
  for (int i = 0, n = exp->getKidCount(); i < n; i++) {
    if (ExpressionPtr k = exp->getNthExpr(i)) {
      exp->setNthKid(i, cloneForInlineRecur(info, k, prefix, ar, scope));
    }
  }
  StaticClassName *scn = dynamic_cast<StaticClassName*>(exp.get());
  if (scn && scn->isStatic() && !info.staticClass.empty()) {
    scn->resolveStatic(info.staticClass);
  }
  switch (exp->getKindOf()) {
  case Expression::KindOfSimpleVariable:
    {
      SimpleVariablePtr sv(dynamic_pointer_cast<SimpleVariable>(exp));
      if (sv->isSuperGlobal()) break;
      string name;
      if (sv->isThis()) {
        if (!info.callWithThis) {
          if (!sv->hasContext(Expression::ObjectContext)) {
            exp = sv->makeConstant(ar, "null");
          } else {
            // This will produce the wrong error
            // we really want a "throw_fatal" ast node.
            exp = sv->makeConstant(ar, "null");
          }
          break;
        }
        if (info.localThis.empty()) break;
        name = info.localThis;
      } else {
        name = prefix + sv->getName();
      }
      SimpleVariablePtr rep(new SimpleVariable(
                              exp->getScope(), exp->getLocation(), name));
      rep->copyContext(sv);
      rep->updateSymbol(SimpleVariablePtr());
      rep->getSymbol()->setHidden();
      // Conservatively set flags to prevent
      // the alias manager from getting confused.
      // On the next pass, it will correct the values,
      // and optimize appropriately.
      rep->getSymbol()->setUsed();
      rep->getSymbol()->setReferenced();
      if (exp->getContext() & (Expression::LValue|
                               Expression::RefValue|
                               Expression::RefParameter)) {
        info.sepm[name] = rep;
      }
      exp = rep;
    }
    break;
  case Expression::KindOfObjectMethodExpression:
  {
    FunctionCallPtr call(
      static_pointer_cast<FunctionCall>(exp));
    if (call->getFuncScope() == info.func) {
      call->setNoInline();
    }
    break;
  }
  case Expression::KindOfSimpleFunctionCall:
    {
      SimpleFunctionCallPtr call(static_pointer_cast<SimpleFunctionCall>(exp));
      call->addLateDependencies(ar);
      call->setLocalThis(info.localThis);
      if (call->getFuncScope() == info.func) {
        call->setNoInline();
      }
    }
  default:
    break;
  }
  return exp;
}
Пример #10
0
/*
  Determine whether the rhs behaves normally, or abnormally.

  1) If the expression is the silence operator, recurse on the inner expression.
  2) If the expression is a list assignment expression, recurse on the
     RHS of the expression.
  3) If the expression is one of the following, then E behaves normally:
  Simple/Dynamic variable (including $this and superglobals)
  Array element expression
  Property expression
  Static variable expression
  Function call expression
  Preinc/predec expression (but not postinc/postdec)
  Assignment expression
  Assignment op expression
  Binding assignment expression
  Include/require expression
  Eval expression
  Array expression
  Array cast expression
  4) For all other expressions, E behaves abnormally. This includes:
  All binary operator expressions
  All unary operator expressions except silence and preinc/predec
  Scalar expression of type null, bool, int, double, or string
  Qop expression (?:)
  Constant expression
  Class constant expression
  Isset or empty expression
  Exit expression
  Instanceof expression
  Anonymous class expression
*/
static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
  switch (rhs->getKindOf()) {
  case Construct::KindOfSimpleVariable:
  case Construct::KindOfDynamicVariable:
  case Construct::KindOfArrayElementExpression:
  case Construct::KindOfObjectPropertyExpression:
  case Construct::KindOfStaticMemberExpression:
  case Construct::KindOfSimpleFunctionCall:
  case Construct::KindOfDynamicFunctionCall:
  case Construct::KindOfObjectMethodExpression:
  case Construct::KindOfNewObjectExpression:
  case Construct::KindOfAssignmentExpression:
  case Construct::KindOfExpressionList:
  case Construct::KindOfIncludeExpression:
  case Construct::KindOfYieldExpression:
  case Construct::KindOfYieldFromExpression:
  case Construct::KindOfAwaitExpression:
  case Construct::KindOfClassExpression:
    return ListAssignment::Regular;

  case Construct::KindOfListAssignment:
    return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());

  case Construct::KindOfUnaryOpExpression: {
    auto u = static_pointer_cast<UnaryOpExpression>(rhs);
    switch (u->getOp()) {
      case '@':
        return GetRHSKind(u->getExpression());
      case T_INC:
      case T_DEC:
        return u->getFront() ?
          ListAssignment::Regular : ListAssignment::Checked;
      case T_EVAL:
      case T_ARRAY:
      case T_ARRAY_CAST:
        return ListAssignment::Regular;
      default:
        return ListAssignment::Null;
    }
    break;
  }

  case Construct::KindOfBinaryOpExpression: {
    auto b = static_pointer_cast<BinaryOpExpression>(rhs);
    if (b->isAssignmentOp() ||
        b->getOp() == '+' ||
        b->getOp() == T_COLLECTION) {
      return ListAssignment::Regular;
    }
    return ListAssignment::Null;
  }
  case Construct::KindOfQOpExpression:
  case Construct::KindOfNullCoalesceExpression:
    return ListAssignment::Checked;

  // invalid context
  case Construct::KindOfExpression:
  case Construct::KindOfArrayPairExpression:
  case Construct::KindOfParameterExpression:
  case Construct::KindOfModifierExpression:
  case Construct::KindOfUserAttribute:
    always_assert(false);

  // non-arrays
  case Construct::KindOfScalarExpression:
  case Construct::KindOfConstantExpression:
  case Construct::KindOfClassConstantExpression:
  case Construct::KindOfEncapsListExpression:
  case Construct::KindOfClosureExpression:
    return ListAssignment::Null;

#define STATEMENT_CASE(x) case Construct::KindOf##x:
  DECLARE_STATEMENT_TYPES(STATEMENT_CASE) {
    always_assert(false);
  }
#undef STATEMENT_CASE
  }

  // unreachable for known expression kinds
  always_assert(false);
}
Пример #11
0
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);
        }
      }
    }
  }
}
Пример #12
0
/*
  Determine whether the rhs behaves normally, or abnormally.

  1) If the expression is the silence operator, recurse on the inner expression.
  2) If the expression is a list assignment expression, recurse on the
     RHS of the expression.
  3) If the expression is one of the following, then E behaves normally:
  Simple/Dynamic variable (including $this and superglobals)
  Array element expression
  Property expression
  Static variable expression
  Function call expression
  Preinc/predec expression (but not postinc/postdec)
  Assignment expression
  Assignment op expression
  Binding assignment expression
  Include/require expression
  Eval expression
  Array expression
  Array cast expression
  4) For all other expressions, E behaves abnormally. This includes:
  All binary operator expressions
  All unary operator expressions except silence and preinc/predec
  Scalar expression of type null, bool, int, double, or string
  Qop expression (?:)
  Constant expression
  Class constant expression
  Isset or empty expression
  Exit expression
  Instanceof expression
*/
static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
  switch (rhs->getKindOf()) {
    case Expression::KindOfSimpleVariable:
    case Expression::KindOfDynamicVariable:
    case Expression::KindOfArrayElementExpression:
    case Expression::KindOfObjectPropertyExpression:
    case Expression::KindOfStaticMemberExpression:
    case Expression::KindOfSimpleFunctionCall:
    case Expression::KindOfDynamicFunctionCall:
    case Expression::KindOfObjectMethodExpression:
    case Expression::KindOfNewObjectExpression:
    case Expression::KindOfAssignmentExpression:
    case Expression::KindOfExpressionList:
    case Expression::KindOfIncludeExpression:
    case Expression::KindOfYieldExpression:
    case Expression::KindOfAwaitExpression:
    case Expression::KindOfQueryExpression:
      return ListAssignment::Regular;

    case Expression::KindOfListAssignment:
      return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());

    case Expression::KindOfUnaryOpExpression: {
      UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(rhs));
      switch (u->getOp()) {
        case '@':
          return GetRHSKind(u->getExpression());
        case T_INC:
        case T_DEC:
          return u->getFront() ?
            ListAssignment::Regular : ListAssignment::Checked;
        case T_EVAL:
        case T_ARRAY:
        case T_ARRAY_CAST:
          return ListAssignment::Regular;
        default:
          return ListAssignment::Null;
      }
      break;
    }

    case Expression::KindOfBinaryOpExpression: {
      BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(rhs));
      if (b->isAssignmentOp() ||
          b->getOp() == '+' ||
          b->getOp() == T_COLLECTION) {
        return ListAssignment::Regular;
      }
      return ListAssignment::Null;
    }
    case Expression::KindOfQOpExpression:
      return ListAssignment::Checked;

    // invalid context
    case Expression::KindOfArrayPairExpression:
    case Expression::KindOfParameterExpression:
    case Expression::KindOfModifierExpression:
    case Expression::KindOfUserAttribute:
    case Expression::KindOfFromClause:
    case Expression::KindOfLetClause:
    case Expression::KindOfWhereClause:
    case Expression::KindOfSelectClause:
    case Expression::KindOfIntoClause:
    case Expression::KindOfJoinClause:
    case Expression::KindOfGroupClause:
    case Expression::KindOfOrderbyClause:
    case Expression::KindOfOrdering:
      always_assert(false);

    // non-arrays
    case Expression::KindOfScalarExpression:
    case Expression::KindOfConstantExpression:
    case Expression::KindOfClassConstantExpression:
    case Expression::KindOfEncapsListExpression:
    case Expression::KindOfClosureExpression:
      return ListAssignment::Null;
  }

  // unreachable for known expression kinds
  always_assert(false);
}
Пример #13
0
ExpressionPtr AliasManager::canonicalizeNode(ExpressionPtr e) {
  e->setCanonPtr(ExpressionPtr());
  e->setCanonID(0);

  switch (e->getKindOf()) {
  case Expression::KindOfObjectMethodExpression:
  case Expression::KindOfDynamicFunctionCall:
  case Expression::KindOfSimpleFunctionCall:
  case Expression::KindOfNewObjectExpression:
    add(m_bucketMap[0], e);
    break;

  case Expression::KindOfListAssignment:
    add(m_bucketMap[0], e);
    break;

  case Expression::KindOfAssignmentExpression: {
    AssignmentExpressionPtr ae = spc(AssignmentExpression,e);
    if (e->getContext() & Expression::DeadStore) {
      Construct::recomputeEffects();
      return ae->getValue();
    }
    ExpressionPtr rep;
    int interf = findInterf(ae->getVariable(), false, rep);
    if (interf == SameAccess) {
      switch (rep->getKindOf()) {
      default:
        break;
      case Expression::KindOfAssignmentExpression:
        {
          AssignmentExpressionPtr a = spc(AssignmentExpression, rep);
          ExpressionPtr value = a->getValue();
          if (a->getValue()->getContext() & Expression::RefValue) {
            break;
          }
        }
      case Expression::KindOfUnaryOpExpression:
      case Expression::KindOfBinaryOpExpression:
        rep->setContext(Expression::DeadStore);
        break;
      }
    }
    add(m_bucketMap[0], e);
    break;
  }

  case Expression::KindOfConstantExpression:
  case Expression::KindOfSimpleVariable:
  case Expression::KindOfDynamicVariable:
  case Expression::KindOfArrayElementExpression:
  case Expression::KindOfObjectPropertyExpression:
  case Expression::KindOfStaticMemberExpression:
    if (!(e->getContext() & (Expression::AssignmentLHS|
                             Expression::DeepAssignmentLHS|
                             Expression::OprLValue))) {
      if (!(e->getContext() & (Expression::LValue|
                               Expression::RefValue|
                               Expression::RefParameter|
                               Expression::UnsetContext))) {
        ExpressionPtr rep;
        int interf = findInterf(e, true, rep);
        if (interf == SameAccess) {
          if (rep->getKindOf() == e->getKindOf()) {
            e->setCanonID(rep->getCanonID());
            e->setCanonPtr(rep);
            return ExpressionPtr();
          }
          if (rep->getKindOf() == Expression::KindOfAssignmentExpression) {
            ExpressionPtr rhs = spc(AssignmentExpression,rep)->getValue();
            if (rhs->is(Expression::KindOfScalarExpression)) {
              rhs = rhs->clone();
              getCanonical(rhs);
              return rhs;
            }
            e->setCanonPtr(rhs);
          }
        }
      }
      add(m_bucketMap[0], e);
    } else {
      getCanonical(e);
    }
    break;

  case Expression::KindOfBinaryOpExpression: {
    BinaryOpExpressionPtr bop = spc(BinaryOpExpression, e);

    int rop = getOpForAssignmentOp(bop->getOp());
    if (rop) {
      ExpressionPtr lhs = bop->getExp1();
      ExpressionPtr rep;
      if (bop->getContext() & Expression::DeadStore) {
        Construct::recomputeEffects();
        ExpressionPtr rhs = bop->getExp2()->clone();
        lhs = lhs->clone();
        lhs->clearContext(Expression::LValue);
        lhs->clearContext(Expression::NoLValueWrapper);
        lhs->clearContext(Expression::OprLValue);
        rep = ExpressionPtr
          (new BinaryOpExpression(e->getLocation(),
                                  Expression::KindOfBinaryOpExpression,
                                  lhs, rhs, rop));

      } else {
        ExpressionPtr alt;
        int interf = findInterf(lhs, true, alt);
        if (interf == SameAccess &&
            alt->is(Expression::KindOfAssignmentExpression)) {
          ExpressionPtr op0 = spc(AssignmentExpression,alt)->getValue();
          if (op0->is(Expression::KindOfScalarExpression)) {
            ExpressionPtr op1 = bop->getExp2();
            ExpressionPtr rhs
              (new BinaryOpExpression(e->getLocation(),
                                      Expression::KindOfBinaryOpExpression,
                                      op0->clone(), op1->clone(), rop));

            lhs = lhs->clone();
            lhs->clearContext(Expression::OprLValue);
            rep = ExpressionPtr
              (new AssignmentExpression(e->getLocation(),
                                        Expression::KindOfAssignmentExpression,
                                        lhs, rhs, false));
          }
        }
      }
      if (rep) {
        ExpressionPtr c = canonicalizeRecur(rep);
        return c ? c : rep;
      }
      add(m_bucketMap[0], e);
    } else {
      getCanonical(e);
    }
    break;
  }

  case Expression::KindOfUnaryOpExpression:
    {
      UnaryOpExpressionPtr uop = spc(UnaryOpExpression, e);
      switch (uop->getOp()) {
      case T_INC:
      case T_DEC:
        if (uop->getContext() & Expression::DeadStore) {
          Construct::recomputeEffects();
          ExpressionPtr val = uop->getExpression()->clone();
          val->clearContext(Expression::LValue);
          val->clearContext(Expression::NoLValueWrapper);
          val->clearContext(Expression::OprLValue);
          if (uop->getFront()) {
            ExpressionPtr inc
              (new ScalarExpression(uop->getLocation(),
                                    Expression::KindOfScalarExpression,
                                    T_LNUMBER, string("1")));

            val = ExpressionPtr
              (new BinaryOpExpression(uop->getLocation(),
                                      Expression::KindOfBinaryOpExpression,
                                      val, inc,
                                      uop->getOp() == T_INC ? '+' : '-'));

          }

          ExpressionPtr r = canonicalizeRecur(val);
          return r ? r : val;
        }
        add(m_bucketMap[0], e);
        break;
      default:
        getCanonical(e);
        break;
      }
      break;
    }

  default:
    getCanonical(e);
    break;
  }

  return ExpressionPtr();
}
Пример #14
0
int AliasManager::findInterf(ExpressionPtr rv, bool isLoad,
                             ExpressionPtr &rep) {
  BucketMapEntry lvs = m_bucketMap[0];

  rep = ExpressionPtr();
  ExpressionPtrList::reverse_iterator it = lvs.rbegin(), end = lvs.rend();
  int a;

  int depth = 0, min_depth = 0, max_depth = 0;
  while (it != end) {
    ExpressionPtr e = *it++;
    switch (e->getKindOf()) {
    case Expression::KindOfScalarExpression:
      {
        ScalarExpressionPtr se = spc(ScalarExpression, e);
        const std::string &s = se->getString();
        if (s == "begin") {
          depth--;
          if (depth < min_depth) min_depth = depth;
        } else if (s == "end") {
          depth++;
          if (depth > max_depth) max_depth = depth;
        } else {
          assert(false);
        }
      }
      break;

    case Expression::KindOfObjectMethodExpression:
    case Expression::KindOfDynamicFunctionCall:
    case Expression::KindOfSimpleFunctionCall:
    case Expression::KindOfNewObjectExpression:
      return testAccesses(rv, e);

    case Expression::KindOfListAssignment: {
      ListAssignmentPtr la = spc(ListAssignment, e);
      ExpressionList &lhs = *la->getVariables().get();
      for (int i = lhs.getCount(); i--; ) {
        ExpressionPtr ep = lhs[i];
        if (ep && testAccesses(ep, rv) != DisjointAccess) {
          return InterfAccess;
        }
      }
      break;
    }

    case Expression::KindOfObjectPropertyExpression:
    case Expression::KindOfConstantExpression:
    case Expression::KindOfSimpleVariable:
    case Expression::KindOfDynamicVariable:
    case Expression::KindOfArrayElementExpression:
    case Expression::KindOfStaticMemberExpression:
      a = testAccesses(e, rv);
      if (a == DisjointAccess) {
        continue;
      }
      if (a == SameAccess) {
        if (isLoad) {
          // The value of an earlier load is available
          // if it dominates this one
          if (depth > min_depth) {
            a = InterfAccess;
          }
        } else {
          // The assignment definitely hits the load
          // if it post-dominates it.
          if (min_depth < 0) {
            a = InterfAccess;
          }
        }
      }
      if (a != SameAccess &&
          isLoad && isReadOnlyAccess(e)) {
        continue;
      }
      rep = e;
      return a;

    case Expression::KindOfUnaryOpExpression:
      a = testAccesses(spc(UnaryOpExpression,e)->getExpression(), rv);
      goto handle_assign;
    case Expression::KindOfBinaryOpExpression:
      a = testAccesses(spc(BinaryOpExpression,e)->getExp1(), rv);
      goto handle_assign;
    case Expression::KindOfAssignmentExpression:
      a = testAccesses(spc(AssignmentExpression,e)->getVariable(), rv);
      goto handle_assign;

    handle_assign:
      if (a == DisjointAccess) {
        continue;
      }
      rep = e;
      if (a == SameAccess) {
        if (isLoad) {
          // we can propagate the value of an assignment
          // to a load, provided the assignment dominates
          // the load.
          if (depth > min_depth) {
            a = InterfAccess;
          }
        } else {
          // a later assignment kills an earlier one
          // provided the later one post-dominates the earlier
          if (min_depth < 0) {
            a = InterfAccess;
          }
        }
      }
      return a;

    default:
      break;
    }
  }
  return DisjointAccess;
}
Пример #15
0
int AliasManager::testAccesses(ExpressionPtr e1, ExpressionPtr e2) {
  Expression::KindOf k1 = e1->getKindOf(), k2 = e2->getKindOf();
  while (true) {
    switch (k1) {
    case Expression::KindOfConstantExpression:
      if (e1->canonCompare(e2)) return SameAccess;
      switch (k2) {
      case Expression::KindOfObjectMethodExpression:
      case Expression::KindOfDynamicFunctionCall:
      case Expression::KindOfSimpleFunctionCall:
      case Expression::KindOfNewObjectExpression:
        return InterfAccess;
      default:
        return DisjointAccess;
      }
      break;

    case Expression::KindOfArrayElementExpression:
      if (k2 == Expression::KindOfSimpleVariable ||
          k2 == Expression::KindOfDynamicVariable ||
          k2 == Expression::KindOfConstantExpression) {
        break;
      }

      return e1->canonCompare(e2) ?
        SameAccess : InterfAccess;

    case Expression::KindOfStaticMemberExpression:
      if (k2 == Expression::KindOfSimpleVariable ||
          k2 == Expression::KindOfConstantExpression) {
        break;
      }
      return e1->canonCompare(e2) ?
        SameAccess : InterfAccess;

    case Expression::KindOfObjectPropertyExpression:
      if (k2 == Expression::KindOfSimpleVariable ||
          k2 == Expression::KindOfConstantExpression) {
        break;
      }
      return InterfAccess;

    case Expression::KindOfDynamicVariable:
      if (k2 == Expression::KindOfSimpleVariable ||
          k2 == Expression::KindOfConstantExpression) {
        break;
      }

      return e1->canonCompare(e2) ?
        SameAccess : InterfAccess;

    case Expression::KindOfSimpleVariable:
      {
        if (k2 == Expression::KindOfConstantExpression) {
          return DisjointAccess;
        }
        SimpleVariablePtr sv1 = spc(SimpleVariable, e1);
        AliasInfo &ai1 = m_aliasInfo[sv1->getName()];
        switch (k2) {
        case Expression::KindOfSimpleVariable:
          {
            SimpleVariablePtr sv2 = spc(SimpleVariable, e2);
            if (sv1->getName() == sv2->getName()) {
              return SameAccess;
            }
            AliasInfo &ai2 = m_aliasInfo[sv2->getName()];

            if (ai1.getIsRefTo() || ai1.getIsGlobal()) {
              return m_wildRefs || ai2.getIsGlobal() || ai2.checkRefLevel(0) ?
                InterfAccess : DisjointAccess;
            }

            if (ai2.getIsRefTo() || ai2.getIsGlobal()) {
              return m_wildRefs || ai1.getIsGlobal() || ai1.checkRefLevel(0) ?
                InterfAccess : DisjointAccess;
            }
          }
          return DisjointAccess;

        case Expression::KindOfDynamicVariable:
          return InterfAccess;

        case Expression::KindOfArrayElementExpression:
          if (ai1.getIsRefTo() || ai1.getIsGlobal() ||
              m_wildRefs || ai1.checkRefLevel(0)) {
            return InterfAccess;
          } else {
            // $a = "foo"; $a[0] = "x";
            ExpressionPtr var = spc(ArrayElementExpression, e2)->getVariable();
            if (e1->canonCompare(var)) {
              return InterfAccess;
            }
          }
          return DisjointAccess;

        case Expression::KindOfStaticMemberExpression:
        case Expression::KindOfObjectPropertyExpression:
        default:
          if (ai1.getIsRefTo() || ai1.getIsGlobal() || m_wildRefs) {
            return InterfAccess;
          }
          return DisjointAccess;
        }
        // mustnt get here (we would loop forever).
        ASSERT(false);
      }

    default:
      return InterfAccess;
    }

    ExpressionPtr t = e1;
    e1 = e2;
    e2 = t;
    k1 = k2;
    k2 = e2->getKindOf();
  }
}