Beispiel #1
0
TypePtr Symbol::setType(AnalysisResultConstPtr ar, BlockScopeRawPtr scope,
                        TypePtr type, bool coerced) {
  if (!type) return type;
  if (ar->getPhase() == AnalysisResult::FirstInference) {
    // at this point, you *must* have a lock (if you are user scope)
    if (scope->is(BlockScope::FunctionScope)) {
      FunctionScopeRawPtr f =
        boost::static_pointer_cast<FunctionScope>(scope);
      if (f->isUserFunction()) {
        f->getInferTypesMutex().assertOwnedBySelf();
      }
    } else if (scope->is(BlockScope::ClassScope)) {
      ClassScopeRawPtr c =
        boost::static_pointer_cast<ClassScope>(scope);
      if (c->isUserClass()) {
        c->getInferTypesMutex().assertOwnedBySelf();
      }
    }
  }
  TypePtr oldType = m_coerced;
  if (!oldType) oldType = Type::Some;
  if (!coerced) return oldType;

  type = CoerceTo(ar, m_coerced, type);
  ASSERT(!isRefClosureVar() || (type && type->is(Type::KindOfVariant)));

  if (ar->getPhase() >= AnalysisResult::AnalyzeAll &&
      !Type::SameType(oldType, type)) {
    triggerUpdates(scope);
  }

  return type;
}
Beispiel #2
0
ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }
  ConstructPtr decl;
  while (!isScalar() && !m_dynamic && !(m_context & LValue)) {
    const Symbol *sym = resolveNS(ar);
    if (!sym) {
      // The constant may be defined in a native extension, so check if its
      // available and persistent.
      auto const cns = Unit::lookupPersistentCns(makeStaticString(m_name));
      if (!cns) break;
      auto const& value = tvAsCVarRef(cns);
      if (!value.isAllowedAsConstantValue()) break;
      auto rep = makeScalarExpression(ar, value);
      rep->setComment(getText());
      copyLocationTo(rep);
      return replaceValue(rep);
    }
    if (!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic()) {
      sym = 0;
      m_dynamic = true;
    }
    if (!sym) break;
    if (!sym->isSystem()) BlockScope::s_constMutex.lock();
    auto value = dynamic_pointer_cast<Expression>(sym->getValue());
    if (!sym->isSystem()) BlockScope::s_constMutex.unlock();

    if (!value || !value->isScalar()) {
      if (!m_depsSet && sym->getDeclaration()) {
        sym->getDeclaration()->getScope()->addUse(
          getScope(), BlockScope::UseKindConstRef);
        m_depsSet = true;
      }
      break;
    }

    Variant scalarValue;
    if (value->getScalarValue(scalarValue) &&
        !scalarValue.isAllowedAsConstantValue()) {
      // block further optimization
      const_cast<Symbol*>(sym)->setDynamic();
      m_dynamic = true;
      break;
    }

    if (sym->isSystem() && !value->is(KindOfScalarExpression)) {
      if (ExpressionPtr opt = value->preOptimize(ar)) {
        value = opt;
      }
    }
    ExpressionPtr rep = Clone(value, getScope());
    rep->setComment(getText());
    copyLocationTo(rep);
    return replaceValue(rep);
  }

  return ExpressionPtr();
}
void ExpressionList::optimize(AnalysisResultConstPtr ar) {
  bool changed = false;
  size_t i = m_exps.size();
  if (m_kind != ListKindParam) {
    size_t skip = m_kind == ListKindLeft ? 0 : i - 1;
    while (i--) {
      if (i != skip) {
        ExpressionPtr &e = m_exps[i];
        if (!e || e->getContainedEffects() == NoEffect) {
          removeElement(i);
          changed = true;
        } else if (e->is(KindOfExpressionList)) {
          ExpressionListPtr el(static_pointer_cast<ExpressionList>(e));
          removeElement(i);
          for (size_t j = el->getCount(); j--; ) {
            insertElement((*el)[j], i);
          }
          changed = true;
        } else if (e->getLocalEffects() == NoEffect) {
          e = e->unneeded();
          // changed already handled by unneeded
        }
      }
    }
    if (m_exps.size() == 1) {
      m_kind = ListKindWrapped;
    } else if (m_kind == ListKindLeft && m_exps[0]->isScalar()) {
      ExpressionPtr e = m_exps[0];
      removeElement(0);
      addElement(e);
      m_kind = ListKindWrapped;
    }
  } else {
    if (hasContext(UnsetContext) &&
        ar->getPhase() >= AnalysisResult::PostOptimize) {
      while (i--) {
        ExpressionPtr &e = m_exps[i];
        if (e->is(Expression::KindOfSimpleVariable)) {
          SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(e);
          if (var->checkUnused()) {
            const std::string &name = var->getName();
            VariableTablePtr variables = getScope()->getVariables();
            if (!variables->isNeeded(name)) {
              removeElement(i);
              changed = true;
            }
          }
        }
      }
    }
  }
  if (changed) {
    getScope()->addUpdates(BlockScope::UseKindCaller);
  }
}
ExpressionPtr ObjectMethodExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }

  if (m_classScope && m_funcScope &&
      (!m_funcScope->isVirtual() ||
       (!ar->isSystem() && !m_funcScope->hasOverride()))) {
    return inliner(ar, m_object, "");
  }

  return ExpressionPtr();
}
Beispiel #5
0
TypePtr ConstantTable::check(BlockScopeRawPtr context,
                             const std::string &name, TypePtr type,
                             bool coerce, AnalysisResultConstPtr ar,
                             ConstructPtr construct,
                             const std::vector<std::string> &bases,
                             BlockScope *&defScope) {
  ASSERT(!m_blockScope.is(BlockScope::FunctionScope));
  bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
  TypePtr actualType;
  defScope = NULL;
  if (name == "true" || name == "false") {
    actualType = Type::Boolean;
  } else {
    Symbol *sym = getSymbol(name);
    if (!sym) {
      if (ar->getPhase() != AnalysisResult::AnalyzeInclude) {
        if (isClassScope) {
          ClassScopeRawPtr parent = findBase(ar, name, bases);
          if (parent) {
            actualType = parent->getConstants()->check(
              context, name, type, coerce, ar, construct, bases, defScope);
            if (defScope) return actualType;
          }
        }
        Compiler::Error(Compiler::UseUndeclaredConstant, construct);
        actualType = isClassScope ? Type::Variant : Type::String;
      }
    } else {
      ASSERT(sym->isPresent());
      ASSERT(sym->getType());
      ASSERT(sym->isConstant());
      defScope = &m_blockScope;
      if (isClassScope) {
        // if the current scope is a function scope, grab the lock.
        // otherwise if it's a class scope, then *try* to grab the lock.
        if (context->is(BlockScope::FunctionScope)) {
          GET_LOCK(BlockScopeRawPtr(&m_blockScope));
          return setType(ar, sym, type, coerce);
        } else {
          TRY_LOCK(BlockScopeRawPtr(&m_blockScope));
          return setType(ar, sym, type, coerce);
        }
      } else {
        Lock lock(m_blockScope.getMutex());
        return setType(ar, sym, type, coerce);
      }
    }
  }

  return actualType;
}
ExpressionPtr IncludeExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
    if (m_include.empty()) {
      bool dr = m_documentRoot;
      m_include = CheckInclude(shared_from_this(), m_exp, dr);
      m_documentRoot = dr;
      m_depsSet = false;
    }
    if (!m_depsSet && !m_include.empty()) {
      analyzeInclude(ar, m_include);
      m_depsSet = true;
    }
  }
  return ExpressionPtr();
}
Beispiel #7
0
ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }
  ConstructPtr decl;
  while (!isScalar() && !m_dynamic && !(m_context & LValue)) {
    const Symbol *sym = resolveNS(ar);
    if (sym &&
        (!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic())) {
      sym = 0;
      m_dynamic = true;
    }
    if (!sym) break;
    if (!sym->isSystem()) BlockScope::s_constMutex.lock();
    auto value = dynamic_pointer_cast<Expression>(sym->getValue());
    if (!sym->isSystem()) BlockScope::s_constMutex.unlock();

    if (!value || !value->isScalar()) {
      if (!m_depsSet && sym->getDeclaration()) {
        sym->getDeclaration()->getScope()->addUse(
          getScope(), BlockScope::UseKindConstRef);
        m_depsSet = true;
      }
      break;
    }

    Variant scalarValue;
    if (value->getScalarValue(scalarValue) &&
        !scalarValue.isAllowedAsConstantValue()) {
      // block further optimization
      const_cast<Symbol*>(sym)->setDynamic();
      m_dynamic = true;
      break;
    }

    if (sym->isSystem() && !value->is(KindOfScalarExpression)) {
      if (ExpressionPtr opt = value->preOptimize(ar)) {
        value = opt;
      }
    }
    ExpressionPtr rep = Clone(value, getScope());
    rep->setComment(getText());
    copyLocationTo(rep);
    return replaceValue(rep);
  }

  return ExpressionPtr();
}
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }
  if (m_class) {
    updateClassName();
    if (m_class) {
      return ExpressionPtr();
    }
  }

  ClassScopePtr cls = resolveClass();
  if (!cls || (cls->isVolatile() && !isPresent())) {
    if (cls && !m_depsSet) {
      cls->addUse(getScope(), BlockScope::UseKindConstRef);
      m_depsSet = true;
    }
    return ExpressionPtr();
  }

  ConstantTablePtr constants = cls->getConstants();
  ClassScopePtr defClass = cls;
  ConstructPtr decl = constants->getValueRecur(ar, m_varName, defClass);
  if (decl) {
    BlockScope::s_constMutex.lock();
    ExpressionPtr value = dynamic_pointer_cast<Expression>(decl);
    BlockScope::s_constMutex.unlock();

    if (!value->isScalar() &&
        (value->is(KindOfClassConstantExpression) ||
         value->is(KindOfConstantExpression))) {
      std::set<ExpressionPtr> seen;
      do {
        if (!seen.insert(value).second) return ExpressionPtr();
        value = value->preOptimize(ar);
        if (!value) return ExpressionPtr();
      } while (!value->isScalar() &&
               (value->is(KindOfClassConstantExpression) ||
                value->is(KindOfConstantExpression)));
    }

    ExpressionPtr rep = Clone(value, getScope());
    rep->setComment(getText());
    copyLocationTo(rep);
    return replaceValue(rep);
  }
  return ExpressionPtr();
}
Beispiel #9
0
TypePtr ConstantTable::check(const std::string &name, TypePtr type,
                             bool coerce, AnalysisResultConstPtr ar,
                             ConstructPtr construct,
                             const std::vector<std::string> &bases,
                             BlockScope *&defScope) {
  TypePtr actualType;
  defScope = NULL;
  if (name == "true" || name == "false") {
    actualType = Type::Boolean;
  } else {
    Symbol *sym = genSymbol(name, true);
    if (!sym->valueSet()) {
      if (ar->getPhase() != AnalysisResult::AnalyzeInclude) {
        actualType = checkBases(name, type, coerce, ar, construct,
                                bases, defScope);
        if (defScope) return actualType;
        Compiler::Error(Compiler::UseUndeclaredConstant, construct);
        if (m_blockScope.is(BlockScope::ClassScope)) {
          actualType = Type::Variant;
        } else {
          actualType = Type::String;
        }
        setType(ar, sym, actualType, true);
      }
    } else {
      if (sym->getType()) {
        defScope = &m_blockScope;
        actualType = sym->getType();
        if (actualType->is(Type::KindOfSome) ||
            actualType->is(Type::KindOfAny)) {
          setType(ar, sym, type, true);
          return type;
        }
      } else {
        actualType = checkBases(name, type, coerce, ar, construct,
                                bases, defScope);
        if (defScope) return actualType;
        actualType = Type::Some;
        setType(ar, sym, actualType, true);
        sym->setDeclaration(construct);
      }
    }
  }

  return actualType;
}
Beispiel #10
0
TypePtr Symbol::setType(AnalysisResultConstPtr ar, BlockScopeRawPtr scope,
                        TypePtr type, bool coerced) {
  if (!type) return type;

  TypePtr oldType = m_coerced;
  if (!oldType) oldType = Type::Some;
  if (!coerced) return oldType;

  type = CoerceTo(ar, m_coerced, type);
  assert(!isRefClosureVar() || (type && type->is(Type::KindOfVariant)));

  if (ar->getPhase() >= AnalysisResult::AnalyzeAll &&
      !Type::SameType(oldType, type)) {
    triggerUpdates(scope);
  }

  return type;
}
ExpressionPtr UnaryOpExpression::preOptimize(AnalysisResultConstPtr ar) {
  Variant value;
  Variant result;

  if (m_exp && ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
    if (m_op == T_UNSET) {
      if (m_exp->isScalar() ||
          (m_exp->is(KindOfExpressionList) &&
           static_pointer_cast<ExpressionList>(m_exp)->getCount() == 0)) {
        recomputeEffects();
        return CONSTANT("null");
      }
      return ExpressionPtr();
    }
  }

  if (m_op == T_ISSET && m_exp->is(KindOfExpressionList) &&
      static_pointer_cast<ExpressionList>(m_exp)->getListKind() ==
      ExpressionList::ListKindParam) {
    ExpressionListPtr el(static_pointer_cast<ExpressionList>(m_exp));
    result = true;
    int i = 0, n = el->getCount();
    for (; i < n; i++) {
      ExpressionPtr e((*el)[i]);
      if (!e || !e->isScalar() || !e->getScalarValue(value)) break;
      if (!isset(value)) {
        result = false;
      }
    }
    if (i == n) {
      return replaceValue(makeScalarExpression(ar, result));
    }
  } else if (m_op != T_ARRAY &&
      m_exp &&
      m_exp->isScalar() &&
      m_exp->getScalarValue(value) &&
      preCompute(value, result)) {
    return replaceValue(makeScalarExpression(ar, result));
  }
  return ExpressionPtr();
}
ExpressionPtr ObjectMethodExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }

  if (m_classScope && m_funcScope &&
      (!m_funcScope->isVirtual() ||
       (Option::WholeProgram && !m_funcScope->hasOverride()))) {

    if (Option::DynamicInvokeFunctions.size()) {
      if (Option::DynamicInvokeFunctions.find(
            m_classScope->getName() + "::" + m_funcScope->getName()) !=
          Option::DynamicInvokeFunctions.end()) {
        setNoInline();
      }
    }

    return inliner(ar, m_object, "");
  }

  return ExpressionPtr();
}
ExpressionPtr UnaryOpExpression::preOptimize(AnalysisResultConstPtr ar) {
  Variant value;
  Variant result;

  if (m_exp && ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
    if (m_op == T_UNSET) {
      if (m_exp->isScalar() ||
          (m_exp->is(KindOfExpressionList) &&
           static_pointer_cast<ExpressionList>(m_exp)->getCount() == 0)) {
        recomputeEffects();
        return CONSTANT("null");
      }
      return ExpressionPtr();
    }
  }

  if (m_op == T_ISSET && m_exp->is(KindOfExpressionList) &&
      static_pointer_cast<ExpressionList>(m_exp)->getListKind() ==
      ExpressionList::ListKindParam) {
    ExpressionListPtr el(static_pointer_cast<ExpressionList>(m_exp));
    result = true;
    int i = 0, n = el->getCount();
    for (; i < n; i++) {
      ExpressionPtr e((*el)[i]);
      if (!e || !e->isScalar() || !e->getScalarValue(value)) break;
      if (!isset(value)) {
        result = false;
      }
    }
    if (i == n) {
      return replaceValue(makeScalarExpression(ar, result));
    }
  } else if (m_op != T_ARRAY &&
             m_exp &&
             m_exp->isScalar() &&
             m_exp->getScalarValue(value) &&
             preCompute(value, result)) {
    return replaceValue(makeScalarExpression(ar, result));
  } else if (m_op == T_BOOL_CAST) {
    switch (m_exp->getKindOf()) {
      default: break;
      case KindOfBinaryOpExpression: {
        int op = static_pointer_cast<BinaryOpExpression>(m_exp)->getOp();
        switch (op) {
          case T_LOGICAL_OR:
          case T_BOOLEAN_OR:
          case T_LOGICAL_AND:
          case T_BOOLEAN_AND:
          case T_LOGICAL_XOR:
          case T_INSTANCEOF:
          case '<':
          case T_IS_SMALLER_OR_EQUAL:
          case '>':
          case T_IS_GREATER_OR_EQUAL:
          case T_IS_IDENTICAL:
          case T_IS_NOT_IDENTICAL:
          case T_IS_EQUAL:
          case T_IS_NOT_EQUAL:
            return m_exp;
        }
        break;
      }
      case KindOfUnaryOpExpression: {
        int op = static_pointer_cast<UnaryOpExpression>(m_exp)->getOp();
        switch (op) {
          case T_BOOL_CAST:
          case '!':
          case T_ISSET:
          case T_EMPTY:
          case T_PRINT:
            return m_exp;
        }
        break;
      }
    }
  }
  return ExpressionPtr();
}
ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) {
  if (Option::EliminateDeadCode &&
      ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
    // otherwise used & needed flags may not be up to date yet
    ExpressionPtr rep = optimize(ar);
    if (rep) return rep;
  }
  if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) {
    return ExpressionPtr();
  }
  ExpressionPtr val = m_value;
  while (val) {
    if (val->is(KindOfExpressionList)) {
      ExpressionListPtr el(static_pointer_cast<ExpressionList>(val));
      val = el->listValue();
      continue;
    }
    if (val->is(KindOfAssignmentExpression)) {
      val = static_pointer_cast<AssignmentExpression>(val)->m_value;
      continue;
    }
    break;
  }
  if (val && val->isScalar()) {
    if (val != m_value) {
      ExpressionListPtr rep(new ExpressionList(
                              getScope(), getLocation(),
                              KindOfExpressionList,
                              ExpressionList::ListKindWrapped));
      rep->addElement(m_value);
      m_value = val->clone();
      rep->addElement(static_pointer_cast<Expression>(shared_from_this()));
      return replaceValue(rep);
    }
    if (!m_ref && m_variable->is(KindOfArrayElementExpression)) {
      ArrayElementExpressionPtr ae(
        static_pointer_cast<ArrayElementExpression>(m_variable));
      ExpressionPtr avar(ae->getVariable());
      ExpressionPtr aoff(ae->getOffset());
      if (!aoff || aoff->isScalar()) {
        avar = avar->getCanonLVal();
        while (avar) {
          if (avar->isScalar()) {
            Variant v,o,r;
            if (!avar->getScalarValue(v)) break;
            if (!val->getScalarValue(r)) break;
            try {
              g_context->setThrowAllErrors(true);
              if (aoff) {
                if (!aoff->getScalarValue(o)) break;
                v.set(o, r);
              } else {
                v.append(r);
              }
              g_context->setThrowAllErrors(false);
            } catch (...) {
              break;
            }
            ExpressionPtr rep(
              new AssignmentExpression(
                getScope(), getLocation(), KindOfAssignmentExpression,
                m_variable->replaceValue(Clone(ae->getVariable())),
                makeScalarExpression(ar, v), false));
            if (!isUnused()) {
              ExpressionListPtr el(
                new ExpressionList(
                  getScope(), getLocation(), KindOfExpressionList,
                  ExpressionList::ListKindWrapped));
              el->addElement(rep);
              el->addElement(val);
              rep = el;
            }
            return replaceValue(rep);
          }
          avar = avar->getCanonPtr();
        }
        g_context->setThrowAllErrors(false);
      }
    }
  }
  return ExpressionPtr();
}
Beispiel #15
0
StatementPtr IfStatement::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return StatementPtr();
  }

  // we cannot optimize away the code inside if statement, because
  // there may be a goto that goes into if statement.
  if (hasReachableLabel()) {
    return StatementPtr();
  }

  bool changed = false;
  int i;
  int j;
  Variant value;
  bool hoist = false;
  for (i = 0; i < m_stmts->getCount(); i++) {
    IfBranchStatementPtr branch =
      dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[i]);
    ExpressionPtr condition = branch->getCondition();
    if (!condition) {
      StatementPtr stmt = branch->getStmt();
      if (stmt) {
        if (!i &&
            ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) ||
             !stmt->hasDecl())) {
          hoist = true;
          break;
        }
        if (stmt->is(KindOfIfStatement)) {
          StatementListPtr sub_stmts =
            dynamic_pointer_cast<IfStatement>(stmt)->m_stmts;
          m_stmts->removeElement(i);
          changed = true;
          for (j = 0; j < sub_stmts->getCount(); j++) {
            m_stmts->insertElement((*sub_stmts)[j], i++);
          }
        }
      }
      break;
    } else if (condition->getEffectiveScalar(value)) {
      if (value.toBoolean()) {
        hoist = !i &&
          ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) ||
           !branch->hasDecl());
        break;
      } else if (!condition->hasEffect()) {
        m_stmts->removeElement(i--);
        changed = true;
      } else if (branch->getStmt()) {
        branch->clearStmt();
        changed = true;
      }
    }
  }

  if (!changed && i && i == m_stmts->getCount()) return StatementPtr();

  // either else branch or if (true) branch without further declarations

  i++;
  while (i < m_stmts->getCount()) {
    m_stmts->removeElement(i);
    changed = true;
  }

  // if there is only one branch left, return stmt.
  if (hoist) {
    IfBranchStatementPtr branch =
      dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[0]);
    return branch->getStmt() ? branch->getStmt() : NULL_STATEMENT();
  } else if (m_stmts->getCount() == 0) {
    return NULL_STATEMENT();
  } else {
    return changed ? static_pointer_cast<Statement>(shared_from_this())
                   : StatementPtr();
  }
}
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getRange(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getRange(),
                rep, T_BOOL_CAST, true));
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            auto binOpExp = dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              auto aExp = m_exp1;
              auto bExp = binOpExp->m_exp1;
              auto cExp = binOpExp->m_exp2;
              if (aExp->isArray() || bExp->isArray() || cExp->isArray()) {
                break;
              }
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (auto optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      auto scalar1 = dynamic_pointer_cast<ScalarExpression>(m_exp1);
      auto scalar2 = dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if ((!Option::WholeProgram || !Option::ParseTimeOpts) && getScope()) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        auto cs = getClassScope();
        if (cs && cs->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      auto add = RuntimeOption::IntsOverflowToInts ? cellAdd : cellAddO;
      auto sub = RuntimeOption::IntsOverflowToInts ? cellSub : cellSubO;
      auto mul = RuntimeOption::IntsOverflowToInts ? cellMul : cellMulO;

      switch (m_op) {
        case T_LOGICAL_XOR:
          result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
          break;
        case '|':
          *result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
          break;
        case '&':
          *result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
          break;
        case '^':
          *result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
          break;
        case '.':
          if (v1.isArray() || v2.isArray()) {
            return ExpressionPtr();
          }
          result = concat(v1.toString(), v2.toString());
          break;
        case T_IS_IDENTICAL:
          result = same(v1, v2);
          break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2);
          break;
        case T_IS_EQUAL:
          result = equal(v1, v2);
          break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2);
          break;
        case '<':
          result = less(v1, v2);
          break;
        case T_IS_SMALLER_OR_EQUAL:
          result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '>':
          result = more(v1, v2);
          break;
        case T_IS_GREATER_OR_EQUAL:
          result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case T_SPACESHIP:
          result = cellCompare(*v1.asCell(), *v2.asCell());
          break;
        case '+':
          *result.asCell() = add(*v1.asCell(), *v2.asCell());
          break;
        case '-':
          *result.asCell() = sub(*v1.asCell(), *v2.asCell());
          break;
        case '*':
          *result.asCell() = mul(*v1.asCell(), *v2.asCell());
          break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellDiv(*v1.asCell(), *v2.asCell());
          break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellMod(*v1.asCell(), *v2.asCell());
          break;
        case T_SL: {
          int64_t shift = v2.toInt64();
          if (!RuntimeOption::PHP7_IntSemantics) {
            result = v1.toInt64() << (shift & 63);
          } else if (shift >= 64) {
            result = 0;
          } else if (shift < 0) {
            // This raises an error, and so can't be folded.
            return ExpressionPtr();
          } else {
            result = v1.toInt64() << (shift & 63);
          }
          break;
        }
        case T_SR: {
          int64_t shift = v2.toInt64();
          if (!RuntimeOption::PHP7_IntSemantics) {
            result = v1.toInt64() >> (shift & 63);
          } else if (shift >= 64) {
            result = v1.toInt64() >= 0 ? 0 : -1;
          } else if (shift < 0) {
            // This raises an error, and so can't be folded.
            return ExpressionPtr();
          } else {
            result = v1.toInt64() >> (shift & 63);
          }
          break;
        }
        case T_BOOLEAN_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_BOOLEAN_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_LOGICAL_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_LOGICAL_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_INSTANCEOF: {
          if (v2.isString()) {
            if (v1.isArray() &&
                interface_supports_array(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isString() &&
                interface_supports_string(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isInteger() &&
                interface_supports_int(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isDouble() &&
                interface_supports_double(v2.getStringData())) {
              result = true;
              break;
            }
          }
          result = false;
          break;
        }
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
Beispiel #17
0
StatementPtr ExpStatement::preOptimize(AnalysisResultConstPtr ar) {
  if (ar->getPhase() != AnalysisResult::AnalyzeInclude) {
    m_exp = m_exp->unneeded();
  }
  return StatementPtr();
}
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getLocation(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getLocation(),
                rep, T_BOOL_CAST, true));
          rep->setActualType(Type::Boolean);
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr binOpExp =
              dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              ExpressionPtr aExp = m_exp1;
              ExpressionPtr bExp = binOpExp->m_exp1;
              ExpressionPtr cExp = binOpExp->m_exp2;
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      ScalarExpressionPtr scalar1 =
        dynamic_pointer_cast<ScalarExpression>(m_exp1);
      ScalarExpressionPtr scalar2 =
        dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if (!Option::WholeProgram || !Option::ParseTimeOpts) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        ClassScopeRawPtr clsScope = getOriginalClass();
        if (clsScope && clsScope->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      switch (m_op) {
        case T_LOGICAL_XOR:
          result = logical_xor(v1, v2); break;
        case '|':
          result = bitwise_or(v1, v2); break;
        case '&':
          result = bitwise_and(v1, v2); break;
        case '^':
          result = bitwise_xor(v1, v2); break;
        case '.':
          result = concat(v1, v2); break;
        case T_IS_IDENTICAL:
          result = same(v1, v2); break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2); break;
        case T_IS_EQUAL:
          result = equal(v1, v2); break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2); break;
        case '<':
          result = less(v1, v2); break;
        case T_IS_SMALLER_OR_EQUAL:
          result = less_or_equal(v1, v2); break;
        case '>':
          result = more(v1, v2); break;
        case T_IS_GREATER_OR_EQUAL:
          result = more_or_equal(v1, v2); break;
        case '+':
          result = plus(v1, v2); break;
        case '-':
          result = minus(v1, v2); break;
        case '*':
          result = multiply(v1, v2); break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          result = divide(v1, v2); break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          result = modulo(v1, v2); break;
        case T_SL:
          result = shift_left(v1, v2); break;
        case T_SR:
          result = shift_right(v1, v2); break;
        case T_BOOLEAN_OR:
          result = v1 || v2; break;
        case T_BOOLEAN_AND:
          result = v1 && v2; break;
        case T_LOGICAL_OR:
          result = v1 || v2; break;
        case T_LOGICAL_AND:
          result = v1 && v2; break;
        case T_INSTANCEOF:
          result = false; break;
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
    }
  } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
    switch (m_op) {
      case T_LOGICAL_AND:
      case T_BOOLEAN_AND:
      case T_LOGICAL_OR:
      case T_BOOLEAN_OR: {
        bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND ||
                                           m_op == T_BOOLEAN_AND);
        ExpressionPtr rep = useFirst ? m_exp1 : m_exp2;
        rep = ExpressionPtr(
          new UnaryOpExpression(
            getScope(), getLocation(),
            rep, T_BOOL_CAST, true));
        rep->setActualType(Type::Boolean);
        if (!useFirst) {
          ExpressionListPtr l(
            new ExpressionList(
              getScope(), getLocation(),
              ExpressionList::ListKindComma));
          l->addElement(m_exp1);
          l->addElement(rep);
          l->setActualType(Type::Boolean);
          rep = l;
        }
        rep->setExpectedType(getExpectedType());
        return replaceValue(rep);
      }
      case T_LOGICAL_XOR:
      case '|':
      case '&':
      case '^':
      case '.':
      case '+':
      case '*':
        optExp = foldRightAssoc(ar);
        if (optExp) return optExp;
        break;
      case T_IS_IDENTICAL:
      case T_IS_NOT_IDENTICAL:
        if (v2.isNull()) {
          return makeIsNull(ar, getLocation(), m_exp1,
                            m_op == T_IS_NOT_IDENTICAL);
        }
        break;
      default:
        break;
    }
  }
  return ExpressionPtr();
}
Beispiel #19
0
StatementPtr ExpStatement::preOptimize(AnalysisResultConstPtr ar) {
  assert (ar->getPhase() > AnalysisResult::AnalyzeAll);
  m_exp = m_exp->unneeded();
  return StatementPtr();
}
Beispiel #20
0
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
  ExpressionPtr optExp;
  Variant v1;
  Variant v2;

  if (!m_exp2->getScalarValue(v2)) {
    if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
        m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
      switch (m_op) {
        case T_IS_IDENTICAL:
        case T_IS_NOT_IDENTICAL:
          if (v1.isNull()) {
            return makeIsNull(ar, getLocation(), m_exp2,
                              m_op == T_IS_NOT_IDENTICAL);
          }
          break;
        case T_LOGICAL_AND:
        case T_BOOLEAN_AND:
        case T_LOGICAL_OR:
        case T_BOOLEAN_OR: {
          ExpressionPtr rep =
            v1.toBoolean() == (m_op == T_LOGICAL_AND ||
                               m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
          rep = ExpressionPtr(
              new UnaryOpExpression(
                getScope(), getLocation(),
                rep, T_BOOL_CAST, true));
          rep->setActualType(Type::Boolean);
          return replaceValue(rep);
        }
        case '+':
        case '.':
        case '*':
        case '&':
        case '|':
        case '^':
          if (m_exp2->is(KindOfBinaryOpExpression)) {
            BinaryOpExpressionPtr binOpExp =
              dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
            if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
              ExpressionPtr aExp = m_exp1;
              ExpressionPtr bExp = binOpExp->m_exp1;
              ExpressionPtr cExp = binOpExp->m_exp2;
              if (aExp->isArray() || bExp->isArray() || cExp->isArray()) {
                break;
              }
              m_exp1 = binOpExp = Clone(binOpExp);
              m_exp2 = cExp;
              binOpExp->m_exp1 = aExp;
              binOpExp->m_exp2 = bExp;
              if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
                m_exp1 = optExp;
              }
              return static_pointer_cast<Expression>(shared_from_this());
            }
          }
        break;
        default:
          break;
      }
    }

    return ExpressionPtr();
  }

  if (m_exp1->isScalar()) {
    if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
    try {
      ScalarExpressionPtr scalar1 =
        dynamic_pointer_cast<ScalarExpression>(m_exp1);
      ScalarExpressionPtr scalar2 =
        dynamic_pointer_cast<ScalarExpression>(m_exp2);
      // Some data, like the values of __CLASS__ and friends, are not available
      // while we're still in the initial parse phase.
      if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
        if ((scalar1 && scalar1->needsTranslation()) ||
            (scalar2 && scalar2->needsTranslation())) {
          return ExpressionPtr();
        }
      }
      if (!Option::WholeProgram || !Option::ParseTimeOpts) {
        // In the VM, don't optimize __CLASS__ if within a trait, since
        // __CLASS__ is not resolved yet.
        ClassScopeRawPtr clsScope = getOriginalClass();
        if (clsScope && clsScope->isTrait()) {
          if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
              (scalar2 && scalar2->getType() == T_CLASS_C)) {
            return ExpressionPtr();
          }
        }
      }
      Variant result;
      switch (m_op) {
        case T_LOGICAL_XOR:
          result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
          break;
        case '|':
          *result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
          break;
        case '&':
          *result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
          break;
        case '^':
          *result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
          break;
        case '.':
          if (v1.isArray() || v2.isArray()) {
            return ExpressionPtr();
          }
          result = concat(v1.toString(), v2.toString());
          break;
        case T_IS_IDENTICAL:
          result = same(v1, v2);
          break;
        case T_IS_NOT_IDENTICAL:
          result = !same(v1, v2);
          break;
        case T_IS_EQUAL:
          result = equal(v1, v2);
          break;
        case T_IS_NOT_EQUAL:
          result = !equal(v1, v2);
          break;
        case '<':
          result = less(v1, v2);
          break;
        case T_IS_SMALLER_OR_EQUAL:
          result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '>':
          result = more(v1, v2);
          break;
        case T_IS_GREATER_OR_EQUAL:
          result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
          break;
        case '+':
          *result.asCell() = cellAdd(*v1.asCell(), *v2.asCell());
          break;
        case '-':
          *result.asCell() = cellSub(*v1.asCell(), *v2.asCell());
          break;
        case '*':
          *result.asCell() = cellMul(*v1.asCell(), *v2.asCell());
          break;
        case '/':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellDiv(*v1.asCell(), *v2.asCell());
          break;
        case '%':
          if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
            return ExpressionPtr();
          }
          *result.asCell() = cellMod(*v1.asCell(), *v2.asCell());
          break;
        case T_SL:
          result = v1.toInt64() << v2.toInt64();
          break;
        case T_SR:
          result = v1.toInt64() >> v2.toInt64();
          break;
        case T_BOOLEAN_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_BOOLEAN_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_LOGICAL_OR:
          result = v1.toBoolean() || v2.toBoolean(); break;
        case T_LOGICAL_AND:
          result = v1.toBoolean() && v2.toBoolean(); break;
        case T_INSTANCEOF: {
          if (v2.isString()) {
            if (v1.isArray() &&
                interface_supports_array(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isString() &&
                interface_supports_string(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isInteger() &&
                interface_supports_int(v2.getStringData())) {
              result = true;
              break;
            }
            if (v1.isDouble() &&
                interface_supports_double(v2.getStringData())) {
              result = true;
              break;
            }
          }
          result = false;
          break;
        }
        default:
          return ExpressionPtr();
      }
      return makeScalarExpression(ar, result);
    } catch (...) {
    }
  } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
Beispiel #21
0
StatementPtr InterfaceStatement::preOptimize(AnalysisResultConstPtr ar) {
    if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
        checkVolatile(ar);
    }
    return StatementPtr();
}