ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultPtr ar) {
    if (m_class) ar->preOptimize(m_class);
    ar->preOptimize(m_nameExp);
    ar->preOptimize(m_params);
    if (ar->getPhase() != AnalysisResult::SecondPreOptimize) {
        return ExpressionPtr();
    }
    // optimize away various "exists" functions, this may trigger
    // dead code elimination and improve type-inference.
    if (!m_class && m_className.empty() &&
            (m_type == DefinedFunction ||
             m_type == FunctionExistsFunction ||
             m_type == ClassExistsFunction ||
             m_type == InterfaceExistsFunction) &&
            m_params && m_params->getCount() == 1) {
        ExpressionPtr value = (*m_params)[0];
        if (value->isScalar()) {
            ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value);
            if (name && name->isLiteralString()) {
                string symbol = name->getLiteralString();
                switch (m_type) {
                case DefinedFunction: {
                    ConstantTablePtr constants = ar->getConstants();
                    // system constant
                    if (constants->isPresent(symbol)) {
                        return CONSTANT("true");
                    }
                    // user constant
                    BlockScopePtr block = ar->findConstantDeclarer(symbol);
                    // not found (i.e., undefined)
                    if (!block) {
                        if (symbol.find("::") == std::string::npos) {
                            return CONSTANT("false");
                        } else {
                            // e.g., defined("self::ZERO")
                            return ExpressionPtr();
                        }
                    }
                    constants = block->getConstants();
                    // already set to be dynamic
                    if (constants->isDynamic(symbol)) return ExpressionPtr();
                    ConstructPtr decl = constants->getValue(symbol);
                    ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl);
                    if (constValue->isScalar()) {
                        return CONSTANT("true");
                    } else {
                        return ExpressionPtr();
                    }
                    break;
                }
                case FunctionExistsFunction: {
                    const std::string &lname = Util::toLower(symbol);
                    if (Option::DynamicInvokeFunctions.find(lname) ==
                            Option::DynamicInvokeFunctions.end()) {
                        FunctionScopePtr func = ar->findFunction(lname);
                        if (!func) {
                            return CONSTANT("false");
                        } else if (!func->isVolatile()) {
                            return CONSTANT("true");
                        }
                    }
                    break;
                }
                case InterfaceExistsFunction: {
                    ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
                    if (!cls || !cls->isInterface()) {
                        return CONSTANT("false");
                    } else if (!cls->isVolatile()) {
                        return CONSTANT("true");
                    }
                    break;
                }
                case ClassExistsFunction: {
                    ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
                    if (!cls || cls->isInterface()) {
                        return CONSTANT("false");
                    } else if (!cls->isVolatile()) {
                        return CONSTANT("true");
                    }
                    break;
                }
                default:
                    ASSERT(false);
                }
            }
        }
    }
    return ExpressionPtr();
}
Example #2
0
void Construct::dumpNode(int spc, AnalysisResultConstPtr ar) {
  int nkid = getKidCount();
  const char *name = 0;
  int type = 0;
  std::string scontext = "";
  std::string value = "";
  std::string type_info = "";
  unsigned id = 0;
  ExpressionPtr idPtr = ExpressionPtr();
  int ef = 0;

  if (Statement *s = dynamic_cast<Statement*>(this)) {
    Statement::KindOf stype = s->getKindOf();
    name = Statement::Names[stype];
    value = s->getName();
    type = (int)stype;
  } else if (Expression *e = dynamic_cast<Expression*>(this)) {
    id = e->getCanonID();
    idPtr = e->getCanonLVal();
    ef = e->getLocalEffects();

    Expression::KindOf etype = e->getKindOf();
    name = Expression::Names[etype];
    switch (etype) {
      case Expression::KindOfSimpleFunctionCall:
        value = static_cast<SimpleFunctionCall*>(e)->getName();
        break;
      case Expression::KindOfSimpleVariable:
        value = static_cast<SimpleVariable*>(e)->getName();
        break;
      case Expression::KindOfConstantExpression:
        value = e->getText();
        break;
      case Expression::KindOfScalarExpression:
        value = e->getText();
        break;
      default: break;
    }

    int c = e->getContext();
    if ((c & Expression::Declaration) == Expression::Declaration) {
      scontext += "|Declaration";
    } else if (c & Expression::LValue) {
      scontext += "|LValue";
    }
    if (c & Expression::NoLValueWrapper) {
      scontext += "|NoLValueWrapper";
    }
    if (c & Expression::RefValue) {
      scontext += "|RefValue";
    }
    if (c & Expression::RefParameter) {
      scontext += "|RefParameter";
    }
    if (c & Expression::DeepReference) {
      scontext += "|DeepReference";
    }
    if (c & Expression::NoRefWrapper) {
      scontext += "|NoRefWrapper";
    }
    if (c & Expression::ObjectContext) {
      scontext += "|ObjectContext";
    }
    if (c & Expression::InParameterExpression) {
      scontext += "|InParameterExpression";
    }
    if (c & Expression::ExistContext) {
      scontext += "|ExistContext";
    }
    if (c & Expression::UnsetContext) {
      scontext += "|UnsetContext";
    }
    if (c & Expression::AssignmentLHS) {
      scontext += "|AssignmentLHS";
    }
    if (c & Expression::RefAssignmentLHS) {
      scontext += "|RefAssignmentLHS";
    }
    if (c & Expression::DeepAssignmentLHS) {
      scontext += "|DeepAssignmentLHS";
    }
    if (c & Expression::InvokeArgument) {
      scontext += "|InvokeArgument";
    }
    if (c & Expression::OprLValue) {
      scontext += "|OprLValue";
    }
    if (c & Expression::DeepOprLValue) {
      scontext += "|DeepOprLValue";
    }
    if (c & Expression::AccessContext) {
      scontext += "|AccessContext";
    }

    if (scontext != "") {
      scontext = " (" + scontext.substr(1) + ")";
    }

    type = (int)etype;

    if (e->getActualType()) {
      type_info = e->getActualType()->toString();
      if (e->getExpectedType()) {
        type_info += ":" + e->getExpectedType()->toString();
      }
      if (e->getImplementedType()) {
        type_info += ";" + e->getImplementedType()->toString();
      }
      type_info = "{" + type_info + "} ";
    }
  } else {
    ASSERT(FALSE);
  }

  int s = spc;
  while (s > 0) {
    int n = s > 10 ? 10 : s;
    std::cout << ("          "+10-n);
    s -= n;
  }

  std::cout << "-> 0x" << hex << setfill('0') << setw(10) << (int64)this << dec;

  std::cout << " " << name << "(" << type << ") ";
  if (id) {
    std::cout << "id=" << id << " ";
  }
  if (idPtr) {
    std::cout << "idp=0x" <<
      hex << setfill('0') << setw(10) << (int64)idPtr.get() << " ";
  }

  if (value != "") {
    std::cout << "[" << value << "] ";
  }

  string sef;
  if ((ef & UnknownEffect) == UnknownEffect) {
    sef = "|UnknownEffect";
  } else {
    if (ef & IOEffect) sef += "|IOEffect";
    if (ef & AssignEffect) sef += "|AssignEffect";
    if (ef & GlobalEffect) sef += "|GlobalEffect";
    if (ef & LocalEffect) sef += "|LocalEffect";
    if (ef & ParamEffect) sef += "|ParamEffect";
    if (ef & DeepParamEffect) sef += "|DeepParamEffect";
    if (ef & DynamicParamEffect) sef += "|DynamicParamEffect";
    if (ef & CanThrow) sef += "|CanThrow";
    if (ef & AccessorEffect) sef += "|AccessorEffect";
    if (ef & CreateEffect) sef += "|CreateEffect";
    if (ef & DiagnosticEffect) sef += "|DiagnosticEffect";
    if (ef & OtherEffect) sef += "|OtherEffect";
  }
  if (sef != "") {
    sef = " (" + sef.substr(1) + ")";
  }

  std::cout << type_info << nkid << scontext << sef;
  if (m_loc) {
    std::cout << " " << m_loc->file << ":" <<
      m_loc->line1 << "@" << m_loc->char1;
  }
  std::cout << "\n";
}
Example #3
0
void ExprDict::updateAccess(ExpressionPtr e) {
  int cls = e->getExprClass();
  int eid = e->getCanonID();
  e->clearAnticipated();
  e->clearAvailable();

  // bail on non-canonical expressions
  if (!isCanonicalStructure(eid)) {
    // but record we saw a type assertion belonging to this block
    m_avlTypeAsserts.push_back(eid);
    return;
  }

  if (m_anticipated &&
      (cls & Expression::Update ?
       !BitOps::get_bit(eid, m_altered) : !e->getLocalEffects())) {
    /*
      Anticipated can be computed bottom up as we go. But note that we
      only know altered for Load/Store expressions.
    */
    int i = e->getKidCount();
    while (true) {
      if (!i--) {
        e->setAnticipated();
        if (!e->hasContext(Expression::AssignmentLHS)) {
          setStructureOps(eid, m_anticipated, true);
        }
        break;
      }
      if (ExpressionPtr k = e->getNthExpr(i)) {
        if (!isCanonicalStructure(k->getCanonID())) continue;
        if (!k->isAnticipated()) {
          break;
        }
      }
    }
  }

  if (m_available) {
    /*
      Available has to be computed optimistically, because we dont yet
      know what is going to be altered between here and the end of the block
      So keep a list of the potentially-available accesses (avlAccess), and
      for each id, the last potentially-available expression (avlExpr).
      For each modifying expression that we process, we remove expressions
      from avlAccess, and at the end, we build up the available expressions
      bottom up.
    */
    if ((cls & (Expression::Store|Expression::Call)) ||
        (cls & Expression::Load &&
         e->getContext() & (Expression::LValue|
                            Expression::RefValue|
                            Expression::UnsetContext|
                            Expression::DeepReference))) {
      bool isLoad;
      int depth = 0, effects = 0;
      for (int i = 0, n = m_avlAccess.size(); i < n; ) {
        ExpressionRawPtr a = m_avlAccess[i];
        if (m_am.checkAnyInterf(e, a, isLoad, depth, effects) !=
            AliasManager::DisjointAccess) {
          int aid = a->getCanonID();
          assert(isCanonicalStructure(aid));
          if (eid != aid || cls == Expression::Load) {
            BitOps::set_bit(aid, m_altered, true);
          }
          if (!(cls & Expression::Store) ||
              a != e->getStoreVariable()) {
            a->clearAvailable();
            m_avlAccess[i] = m_avlAccess[--n];
            m_avlAccess.resize(n);
            continue;
          }
        }
        i++;
      }
    }
    if (cls & Expression::Update ||
        !e->getContainedEffects()) {
      int i = e->getKidCount();
      while (true) {
        if (!i--) {
          e->setAvailable();
          if (cls & Expression::Update) {
            m_avlAccess.push_back(e);
          }
          m_avlExpr[eid] = e;
          break;
        }
        if (ExpressionPtr k = e->getNthExpr(i)) {
          if (!isCanonicalStructure(k->getCanonID())) continue;
          if (!k->isAvailable()) {
            break;
          }
        }
      }
    }
  }

  if ((cls & (Expression::Store|Expression::Call)) ||
      (cls & Expression::Load &&
       e->getContext() & (Expression::LValue|
                          Expression::RefValue|
                          Expression::UnsetContext|
                          Expression::DeepReference))) {
    ExpressionPtr cur = m_active, prev;
    bool isLoad;
    int depth = 0, effects = 0;
    while (cur) {
      ExpressionPtr next = cur->getCanonLVal();
      int cid = cur->getCanonID();
      assert(isCanonicalStructure(cid));
      if ((cid != eid || cls == Expression::Load) &&
          (BitOps::get_bit(cid, m_altered) ||
           m_am.checkAnyInterf(e, cur, isLoad, depth, effects) !=
           AliasManager::DisjointAccess)) {
        BitOps::set_bit(cid, m_altered, true);
        if (!prev) {
          m_active = next;
        } else {
          prev->setCanonPtr(next);
        }
      } else {
        prev = cur;
      }
      cur = next;
    }
  }
}
Example #4
0
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(),
                              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;
                if (v.isString()) {
                  if (!o.isInteger() ||
                      o.toInt64Val() < 0 ||
                      o.toInt64Val() >= v.toCStrRef().size()) {
                    // warnings should be raised...
                    break;
                  }
                }
                v.set(o, r);
              } else {
                v.append(r);
              }
              g_context->setThrowAllErrors(false);
            } catch (...) {
              break;
            }
            ExpressionPtr rep(
              new AssignmentExpression(
                getScope(), getLocation(),
                m_variable->replaceValue(Clone(ae->getVariable())),
                makeScalarExpression(ar, v), false));
            if (!isUnused()) {
              ExpressionListPtr el(
                new ExpressionList(
                  getScope(), getLocation(),
                  ExpressionList::ListKindWrapped));
              el->addElement(rep);
              el->addElement(val);
              rep = el;
            }
            return replaceValue(rep);
          }
          avar = avar->getCanonPtr();
        }
        g_context->setThrowAllErrors(false);
      }
    }
  }
  return ExpressionPtr();
}
// 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 = 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 '.':
          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) {
Example #6
0
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
                                   ExpressionListPtr params, bool &valid) {
  if (!params) {
    if (m_minParam > 0) {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
    return 0;
  }

  int ret = 0;
  if (params->getCount() < m_minParam) {
    if (exp->getScope()->isFirstPass()) {
      Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
    }
    valid = false;
    if (!Option::AllDynamic) setDynamic();
  }
  if (params->getCount() > m_maxParam) {
    if (isVariableArgument()) {
      ret = params->getCount() - m_maxParam;
    } else {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooManyArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
  }

  bool canSetParamType = isUserFunction() && !m_overriding && !m_perfectVirtual;
  for (int i = 0; i < params->getCount(); i++) {
    ExpressionPtr param = (*params)[i];
    if (i < m_maxParam && param->hasContext(Expression::RefParameter)) {
      /**
       * This should be very un-likely, since call time pass by ref is a
       * deprecated, not very widely used (at least in FB codebase) feature.
       */
      TRY_LOCK_THIS();
      Symbol *sym = getVariables()->addSymbol(m_paramNames[i]);
      sym->setLvalParam();
      sym->setCallTimeRef();
    }
    if (valid && param->hasContext(Expression::InvokeArgument)) {
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::NoRefWrapper);
    }
    bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument());
    if ((i < m_maxParam && isRefParam(i)) || isRefVararg) {
      param->setContext(Expression::LValue);
      param->setContext(Expression::RefValue);
      param->inferAndCheck(ar, Type::Variant, true);
    } else if (!(param->getContext() & Expression::RefParameter)) {
      param->clearContext(Expression::LValue);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::NoRefWrapper);
    }
    TypePtr expType;
    /**
     * Duplicate the logic of getParamType(i), w/o the mutation
     */
    TypePtr paramType(i < m_maxParam && !isZendParamMode() ?
                      m_paramTypes[i] : TypePtr());
    if (!paramType) paramType = Type::Some;
    if (valid && !canSetParamType && i < m_maxParam &&
        (!Option::HardTypeHints || !m_paramTypeSpecs[i])) {
      /**
       * What is this magic, you might ask?
       *
       * Here, we take advantage of implicit conversion from every type to
       * Variant. Essentially, we don't really care what type comes out of this
       * expression since it'll just get converted anyways. Doing it this way
       * allows us to generate less temporaries along the way.
       */
      TypePtr optParamType(paramType->is(Type::KindOfVariant) ?
                           Type::Some : paramType);
      expType = param->inferAndCheck(ar, optParamType, false);
    } else {
      expType = param->inferAndCheck(ar, Type::Some, false);
    }
    if (i < m_maxParam) {
      if (!Option::HardTypeHints || !m_paramTypeSpecs[i]) {
        if (canSetParamType) {
          if (!Type::SameType(paramType, expType) &&
              !paramType->is(Type::KindOfVariant)) {
            TRY_LOCK_THIS();
            paramType = setParamType(ar, i, expType);
          } else {
            // do nothing - how is this safe?  well, if we ever observe
            // paramType == expType, then this means at some point in the past,
            // somebody called setParamType() with expType.  thus, by calling
            // setParamType() again with expType, we contribute no "new"
            // information. this argument also still applies in the face of
            // concurrency
          }
        }
        // See note above. If we have an implemented type, however, we
        // should set the paramType to the implemented type to avoid an
        // un-necessary cast
        if (paramType->is(Type::KindOfVariant)) {
          TypePtr it(param->getImplementedType());
          paramType = it ? it : expType;
        }
        if (valid) {
          if (!Type::IsLegalCast(ar, expType, paramType) &&
              paramType->isNonConvertibleType()) {
            param->inferAndCheck(ar, paramType, true);
          }
          param->setExpectedType(paramType);
        }
      }
    }
    // we do a best-effort check for bad pass-by-reference and do not report
    // error for some vararg case (e.g., array_multisort can have either ref
    // or value for the same vararg).
    if (!isRefVararg || !isMixedVariableArgument()) {
      Expression::CheckPassByReference(ar, param);
    }
  }
  return ret;
}
Example #7
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);
        }
      }
    }
  }
}
Example #8
0
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                  int state) {
  if (m_kind == ListKindParam && !m_arrayElements) {
    return Expression::preOutputCPP(cg, ar, state|StashKidVars);
  }

  unsigned n = m_exps.size();
  bool inExpression = cg.inExpression();
  if (!inExpression && (state & FixOrder)) {
    return true;
  }

  cg.setInExpression(false);
  bool ret = false;
  if (m_arrayElements) {
    /*
     * would like to do:
     *  ret = Expression::preOutputCPP(cg, ar, state);
     * but icc has problems with the generated code.
     */
    ret = hasEffect();
  } else if (n > 1 && m_kind == ListKindLeft) {
    ret = true;
  } else {
    for (unsigned int i = 0; i < n; i++) {
      if (m_exps[i]->preOutputCPP(cg, ar, 0)) {
        ret = true;
        break;
      }
    }
  }

  if (!inExpression) return ret;

  cg.setInExpression(true);
  if (!ret) {
    if (state & FixOrder) {
      preOutputStash(cg, ar, state);
      return true;
    }
    return false;
  }

  cg.wrapExpressionBegin();
  if (m_arrayElements) {
    setCPPTemp(genCPPTemp(cg, ar));
    outputCPPInternal(cg, ar, true, true);
  } else {
    unsigned ix = m_kind == ListKindLeft ? 0 : n - 1;
    for (unsigned int i = 0; i < n; i++) {
      ExpressionPtr e = m_exps[i];
      e->preOutputCPP(cg, ar, 0);
      if (i != ix) {
        if (e->outputCPPUnneeded(cg, ar)) {
          cg_printf(";\n");
        }
        e->setCPPTemp("/**/");
      } else if (e->hasCPPTemp() && Type::SameType(e->getType(), getType())) {
        setCPPTemp(e->cppTemp());
      } else if (!i && n > 1) {
        e->Expression::preOutputStash(cg, ar, state | FixOrder);
        if (!(state & FixOrder)) {
          cg_printf("id(%s);\n", e->cppTemp().c_str());
        }
        setCPPTemp(e->cppTemp());
      }
    }
  }
  return true;
}
Example #9
0
ExpressionPtr DepthFirstVisitor<Pre, OptVisitor>::visit(ExpressionPtr e) {
  return e->preOptimize(this->m_data.m_ar);
}
TypePtr AssignmentExpression::
inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce,
               ExpressionPtr variable,
               ExpressionPtr value /* = ExpressionPtr() */) {
  TypePtr ret = type;
  if (value) {
    if (coerce) {
      ret = value->inferAndCheck(ar, type, coerce);
    } else {
      ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce);
    }
  }

  BlockScopePtr scope = ar->getScope();
  if (variable->is(Expression::KindOfConstantExpression)) {
    // ...as in ClassConstant statement
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(variable);
    bool p;
    scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p);
  } else if (variable->is(Expression::KindOfDynamicVariable)) {
    // simptodo: not too sure about this
    ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable);
  } else if (variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
    if (var->getName() == "this" && ar->getClassScope()) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(variable, CodeError::ReassignThis,
                                   variable);
      }
    }
    if (ar->getPhase() == AnalysisResult::LastInference && value) {
      if (!value->getExpectedType()) {
        value->setExpectedType(variable->getActualType());
      }
    }
  }
  // if the value may involve object, consider the variable as "referenced"
  // so that objects are not destructed prematurely.
  bool referenced = true;
  if (value && value->isScalar()) referenced = false;
  if (ret && ret->isNoObjectInvolved()) referenced = false;
  if (referenced && variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(variable);
    const std::string &name = var->getName();
    VariableTablePtr variables = ar->getScope()->getVariables();
    variables->addReferenced(name);
  }

  TypePtr vt = variable->inferAndCheck(ar, ret, true);
  if (!coerce && type->is(Type::KindOfAny)) {
    ret = vt;
  }

  return ret;
}
Example #11
0
void test(ExpressionPtr expr)
{
    std::cout << "Before DNF: " << expr->toString() << std::endl;
    std::cout << "After DNF : " << expr->getDNF()->toString() << std::endl << std::endl;
}
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
    bool linemap = outputLineMap(cg, ar, true);

    if (!m_lambda.empty()) {
        cg.printf("\"%s\"", m_lambda.c_str());
        if (linemap) cg.printf(")");
        return;
    }

    if (!m_class && m_className.empty()) {
        if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
            ScalarExpressionPtr name =
                dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
            string varName;
            if (name) {
                varName = name->getIdentifier();
                ExpressionPtr value = (*m_params)[1];
                if (varName.empty()) {
                    cg.printf("throw_fatal(\"bad define\")");
                } else if (m_dynamicConstant) {
                    cg.printf("g->declareConstant(\"%s\", g->%s%s, ",
                              varName.c_str(), Option::ConstantPrefix,
                              varName.c_str());
                    value->outputCPP(cg, ar);
                    cg.printf(")");
                } else {
                    bool needAssignment = true;
                    bool isSystem = ar->getConstants()->isSystem(varName);
                    if (isSystem ||
                            ((!ar->isConstantRedeclared(varName)) && value->isScalar())) {
                        needAssignment = false;
                    }
                    if (needAssignment) {
                        cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str());
                        value->outputCPP(cg, ar);
                    }
                }
            } else {
                cg.printf("throw_fatal(\"bad define\")");
            }
            if (linemap) cg.printf(")");
            return;
        }
        if (m_name == "func_num_args") {
            cg.printf("num_args");
            if (linemap) cg.printf(")");
            return;
        }

        switch (m_type) {
        case VariableArgumentFunction:
        {
            FunctionScopePtr func =
                dynamic_pointer_cast<FunctionScope>(ar->getScope());
            if (func) {
                cg.printf("%s(", m_name.c_str());
                func->outputCPPParamsCall(cg, ar, true);
                if (m_params) {
                    cg.printf(",");
                    m_params->outputCPP(cg, ar);
                }
                cg.printf(")");
                if (linemap) cg.printf(")");
                return;
            }
        }
        break;
        case FunctionExistsFunction:
        case ClassExistsFunction:
        case InterfaceExistsFunction:
        {
            bool literalString = false;
            string symbol;
            if (m_params && m_params->getCount() == 1) {
                ExpressionPtr value = (*m_params)[0];
                if (value->isScalar()) {
                    ScalarExpressionPtr name =
                        dynamic_pointer_cast<ScalarExpression>(value);
                    if (name && name->isLiteralString()) {
                        literalString = true;
                        symbol = name->getLiteralString();
                    }
                }
            }
            if (literalString) {
                switch (m_type) {
                case FunctionExistsFunction:
                {
                    const std::string &lname = Util::toLower(symbol);
                    bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) !=
                                     Option::DynamicInvokeFunctions.end();
                    if (!dynInvoke) {
                        FunctionScopePtr func = ar->findFunction(lname);
                        if (func) {
                            if (!func->isDynamic()) {
                                if (func->isRedeclaring()) {
                                    const char *name = func->getName().c_str();
                                    cg.printf("(%s->%s%s != invoke_failed_%s)",
                                              cg.getGlobals(ar), Option::InvokePrefix,
                                              name, name);
                                    break;
                                }
                                cg.printf("true");
                                break;
                            }
                        } else {
                            cg.printf("false");
                            break;
                        }
                    }
                    cg.printf("f_function_exists(\"%s\")", lname.c_str());
                }
                break;
                case ClassExistsFunction:
                {
                    ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
                    if (cls && !cls->isInterface()) {
                        const char *name = cls->getName().c_str();
                        cg.printf("f_class_exists(\"%s\")", name);
                    } else {
                        cg.printf("false");
                    }
                }
                break;
                case InterfaceExistsFunction:
                {
                    ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
                    if (cls && cls->isInterface()) {
                        const char *name = cls->getName().c_str();
                        cg.printf("f_interface_exists(\"%s\")", name);
                    } else {
                        cg.printf("false");
                    }
                }
                break;
                default:
                    break;
                }
                if (linemap) cg.printf(")");
                return;
            }
        }
        break;
        case GetDefinedVarsFunction:
            cg.printf("get_defined_vars(variables)");
            if (linemap) cg.printf(")");
            return;
        default:
            break;
        }
    }

    outputCPPParamOrderControlled(cg, ar);
    if (linemap) cg.printf(")");
}
void SimpleFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
    outputLineMap(cg, ar);

    if (m_class || !m_className.empty()) {
        if (m_class) {
            m_class->outputPHP(cg, ar);
            cg.printf("::%s(", m_name.c_str());
        } else {
            cg.printf("%s::%s(", m_className.c_str(), m_name.c_str());
        }
    } else {

        if (cg.getOutput() == CodeGenerator::InlinedPHP ||
                cg.getOutput() == CodeGenerator::TrimmedPHP) {

            if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
                    cg.usingStream(CodeGenerator::PrimaryStream) &&
                    Option::DynamicFunctionCalls.find(m_name) !=
                    Option::DynamicFunctionCalls.end()) {
                int funcNamePos = Option::DynamicFunctionCalls[m_name];
                if (m_params && m_params->getCount() &&
                        m_params->getCount() >= funcNamePos + 1) {
                    if (funcNamePos == -1) funcNamePos = m_params->getCount() - 1;
                    ExpressionPtr funcName = (*m_params)[funcNamePos];
                    if (!funcName->is(Expression::KindOfScalarExpression)) {

                        cg.printf("%s(", m_name.c_str());
                        for (int i = 0; i < m_params->getCount(); i++) {
                            if (i > 0) cg.printf(", ");
                            if (i == funcNamePos) {
                                cg.printf("%sdynamic_load(", Option::IdPrefix.c_str());
                                funcName->outputPHP(cg, ar);
                                cg.printf(")");
                            } else {
                                ExpressionPtr param = (*m_params)[i];
                                if (param) param->outputPHP(cg, ar);
                            }
                        }
                        cg.printf(")");
                        return;
                    }
                }
            }
            /* simptodo: I dunno
            if (m_type == RenderTemplateFunction && !m_template.empty()) {
              cg.printf("%s_%s(", m_name.c_str(),
                        Util::getIdentifier(m_template).c_str());
            } else if (m_type == RenderTemplateIncludeFunction) {
              string templateName = ar->getProgram()->getCurrentTemplate();
              cg.printf("%s_%s(", m_name.c_str(),
                        Util::getIdentifier(templateName).c_str());
            } else {
            */
            cg.printf("%s(", m_name.c_str());
            //}

        } else {
            cg.printf("%s(", m_name.c_str());
        }
    }

    if (m_params) m_params->outputPHP(cg, ar);
    cg.printf(")");
}
TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
        bool coerce) {
    reset();

    ConstructPtr self = shared_from_this();

    // handling define("CONSTANT", ...);
    if (!m_class && m_className.empty()) {
        if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
            ScalarExpressionPtr name =
                dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
            string varName;
            if (name) {
                varName = name->getIdentifier();
                if (!varName.empty()) {
                    ExpressionPtr value = (*m_params)[1];
                    TypePtr varType = value->inferAndCheck(ar, NEW_TYPE(Some), false);
                    ar->getDependencyGraph()->
                    addParent(DependencyGraph::KindOfConstant,
                              ar->getName(), varName, self);
                    ConstantTablePtr constants =
                        ar->findConstantDeclarer(varName)->getConstants();
                    if (constants != ar->getConstants()) {
                        if (value && !value->isScalar()) {
                            constants->setDynamic(ar, varName);
                            varType = Type::Variant;
                        }
                        if (constants->isDynamic(varName)) {
                            m_dynamicConstant = true;
                            ar->getScope()->getVariables()->
                            setAttribute(VariableTable::NeedGlobalPointer);
                        } else {
                            constants->setType(ar, varName, varType, true);
                        }
                        // in case the old 'value' has been optimized
                        constants->setValue(ar, varName, value);
                    }
                    return checkTypesImpl(ar, type, Type::Boolean, coerce);
                }
            }
            if (varName.empty() && ar->isFirstPass()) {
                ar->getCodeError()->record(self, CodeError::BadDefine, self);
            }
        } else if (m_type == ExtractFunction) {
            ar->getScope()->getVariables()->forceVariants(ar);
        }
    }

    FunctionScopePtr func;

    // avoid raising both MissingObjectContext and UnknownFunction
    bool errorFlagged = false;

    if (!m_class && m_className.empty()) {
        func = ar->findFunction(m_name);
    } else {
        ClassScopePtr cls = ar->resolveClass(m_className);
        if (cls && cls->isVolatile()) {
            ar->getScope()->getVariables()
            ->setAttribute(VariableTable::NeedGlobalPointer);
        }
        if (!cls || cls->isRedeclaring()) {
            if (cls) {
                m_redeclaredClass = true;
            }
            if (!cls && ar->isFirstPass()) {
                ar->getCodeError()->record(self, CodeError::UnknownClass, self);
            }
            if (m_params) {
                m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
            }
            return checkTypesImpl(ar, type, Type::Variant, coerce);
        }
        m_derivedFromRedeclaring = cls->derivesFromRedeclaring();
        m_validClass = true;

        if (m_name == "__construct") {
            // if the class is known, php will try to identify class-name ctor
            func = cls->findConstructor(ar, true);
        }
        else {
            func = cls->findFunction(ar, m_name, true, true);
        }

        if (func && !func->isStatic()) {
            ClassScopePtr clsThis = ar->getClassScope();
            FunctionScopePtr funcThis = ar->getFunctionScope();
            if (!clsThis ||
                    (clsThis->getName() != m_className &&
                     !clsThis->derivesFrom(ar, m_className)) ||
                    funcThis->isStatic()) {
                // set the method static to avoid "unknown method" runtime exception
                if (Option::StaticMethodAutoFix && !func->containsThis()) {
                    func->setStaticMethodAutoFixed();
                }
                if (ar->isFirstPass()) {
                    ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                               self);
                    errorFlagged = true;
                }
                func.reset();
            }
        }
    }
    if (!func || func->isRedeclaring()) {
        if (func) {
            m_redeclared = true;
            ar->getScope()->getVariables()->
            setAttribute(VariableTable::NeedGlobalPointer);
        }
        if (!func && !errorFlagged && ar->isFirstPass()) {
            ar->getCodeError()->record(self, CodeError::UnknownFunction, self);
        }
        if (m_params) {
            if (func) {
                FunctionScope::RefParamInfoPtr info =
                    FunctionScope::GetRefParamInfo(m_name);
                ASSERT(info);
                for (int i = m_params->getCount(); i--; ) {
                    if (info->isRefParam(i)) {
                        m_params->markParam(i, canInvokeFewArgs());
                    }
                }
            }
            m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
        }
        return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_builtinFunction = !func->isUserFunction();

    if (m_redeclared) {
        if (m_params) {
            m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
        }
        return checkTypesImpl(ar, type, type, coerce);
    }

    CHECK_HOOK(beforeSimpleFunctionCallCheck);

    m_valid = true;
    type = checkParamsAndReturn(ar, type, coerce, func);

    if (!m_valid && m_params) {
        m_params->markParams(false);
    }

    CHECK_HOOK(afterSimpleFunctionCallCheck);

    return type;
}
Example #15
0
void Type::Dump(ExpressionPtr exp) {
  Dump(exp->getExpectedType(), "Expected: %s\t");
  Dump(exp->getActualType(), "Actual: %s\n");
}
Example #16
0
void Construct::dumpNode(int spc, AnalysisResultPtr ar) {
  int nkid = getKidCount();
  std::string name;
  int type = 0;
  std::string scontext = "";
  std::string value = "";
  std::string type_info = "";
  unsigned id = 0;
  ExpressionPtr idPtr = ExpressionPtr();
  int ef = 0;

  if (Statement *s = dynamic_cast<Statement*>(this)) {
    Statement::KindOf stype = s->getKindOf();
    switch (stype) {
    case Statement::KindOfFunctionStatement:
      name="FunctionStatement";
      break;
    case Statement::KindOfClassStatement:
      name="ClassStatement";
      break;
    case Statement::KindOfInterfaceStatement:
      name="InterfaceStatement";
      break;
    case Statement::KindOfClassVariable:
      name="ClassVariable";
      break;
    case Statement::KindOfClassConstant:
      name="ClassConstant";
      break;
    case Statement::KindOfMethodStatement:
      name="MethodStatement";
      break;
    case Statement::KindOfStatementList:
      name="StatementList";
      break;
    case Statement::KindOfBlockStatement:
      name="BlockStatement";
      break;
    case Statement::KindOfIfBranchStatement:
      name="IfBranchStatement";
      break;
    case Statement::KindOfIfStatement:
      name="IfStatement";
      break;
    case Statement::KindOfWhileStatement:
      name="WhileStatement";
      break;
    case Statement::KindOfDoStatement:
      name="DoStatement";
      break;
    case Statement::KindOfForStatement:
      name="ForStatement";
      break;
    case Statement::KindOfSwitchStatement:
      name="SwitchStatement";
      break;
    case Statement::KindOfCaseStatement:
      name="CaseStatement";
      break;
    case Statement::KindOfBreakStatement:
      name="BreakStatement";
      break;
    case Statement::KindOfContinueStatement:
      name="ContinueStatement";
      break;
    case Statement::KindOfReturnStatement:
      name="ReturnStatement";
      break;
    case Statement::KindOfGlobalStatement:
      name="GlobalStatement";
      break;
    case Statement::KindOfStaticStatement:
      name="StaticStatement";
      break;
    case Statement::KindOfEchoStatement:
      name="EchoStatement";
      break;
    case Statement::KindOfUnsetStatement:
      name="UnsetStatement";
      break;
    case Statement::KindOfExpStatement:
      name="ExpStatement";
      break;
    case Statement::KindOfForEachStatement:
      name="ForEachStatement";
      break;
    case Statement::KindOfCatchStatement:
      name="CatchStatement";
      break;
    case Statement::KindOfTryStatement:
      name="TryStatement";
      break;
    case Statement::KindOfThrowStatement:
      name="ThrowStatement";
      break;
    }
    type = (int)stype;
  } else if (Expression *e = dynamic_cast<Expression*>(this)) {
    id = e->getCanonID();
    idPtr = e->getCanonLVal();
    ef = e->getLocalEffects();

    Expression::KindOf etype = e->getKindOf();
    switch (etype) {
    case Expression::KindOfSimpleFunctionCall:
      name="SimpleFunctionCall";
      value = static_cast<SimpleFunctionCall*>(e)->getName();
      break;
    case Expression::KindOfSimpleVariable:
      name="SimpleVariable";
      value = static_cast<SimpleVariable*>(e)->getName();
      break;
    case Expression::KindOfConstantExpression:
      name="ConstantExpression";
      value = e->getText();
      break;
    case Expression::KindOfScalarExpression:
      name="ScalarExpression";
      value = e->getText();
      break;

    case Expression::KindOfExpressionList:
      name="ExpressionList";
      break;
    case Expression::KindOfAssignmentExpression:
      name="AssignmentExpression";
      break;
    case Expression::KindOfDynamicVariable:
      name="DynamicVariable";
      break;
    case Expression::KindOfStaticMemberExpression:
      name="StaticMemberExpression";
      break;
    case Expression::KindOfArrayElementExpression:
      name="ArrayElementExpression";
      break;
    case Expression::KindOfDynamicFunctionCall:
      name="DynamicFunctionCall";
      break;
    case Expression::KindOfObjectPropertyExpression:
      name="ObjectPropertyExpression";
      break;
    case Expression::KindOfObjectMethodExpression:
      name="ObjectMethodExpression";
      break;
    case Expression::KindOfListAssignment:
      name="ListAssignment";
      break;
    case Expression::KindOfNewObjectExpression:
      name="NewObjectExpression";
      break;
    case Expression::KindOfUnaryOpExpression:
      name="UnaryOpExpression";
      break;
    case Expression::KindOfIncludeExpression:
      name="IncludeExpression";
      break;
    case Expression::KindOfBinaryOpExpression:
      name="BinaryOpExpression";
      break;
    case Expression::KindOfQOpExpression:
      name="QOpExpression";
      break;
    case Expression::KindOfArrayPairExpression:
      name="ArrayPairExpression";
      break;
    case Expression::KindOfClassConstantExpression:
      name="ClassConstantExpression";
      break;
    case Expression::KindOfParameterExpression:
      name="ParameterExpression";
      break;
    case Expression::KindOfModifierExpression:
      name="ModifierExpression";
      break;
    case Expression::KindOfEncapsListExpression:
      name="EncapsListExpression";
      break;
    }

    int c = e->getContext();
    if ((c & Expression::Declaration) == Expression::Declaration) {
      scontext += "|Declaration";
    } else if (c & Expression::LValue) {
      scontext += "|LValue";
    }
    if (c & Expression::NoLValueWrapper) {
      scontext += "|NoLValueWrapper";
    }
    if (c & Expression::RefValue) {
      scontext += "|RefValue";
    }
    if (c & Expression::RefParameter) {
      scontext += "|RefParameter";
    }
    if (c & Expression::DeepReference) {
      scontext += "|DeepReference";
    }
    if (c & Expression::NoRefWrapper) {
      scontext += "|NoRefWrapper";
    }
    if (c & Expression::ObjectContext) {
      scontext += "|ObjectContext";
    }
    if (c & Expression::InParameterExpression) {
      scontext += "|InParameterExpression";
    }
    if (c & Expression::ExistContext) {
      scontext += "|ExistContext";
    }
    if (c & Expression::UnsetContext) {
      scontext += "|UnsetContext";
    }
    if (c & Expression::AssignmentLHS) {
      scontext += "|AssignmentLHS";
    }
    if (c & Expression::DeepAssignmentLHS) {
      scontext += "|DeepAssignmentLHS";
    }
    if (c & Expression::InvokeArgument) {
      scontext += "|InvokeArgument";
    }
    if (c & Expression::OprLValue) {
      scontext += "|OprLValue";
    }
    if (c & Expression::DeepOprLValue) {
      scontext += "|DeepOprLValue";
    }
    if (c & Expression::AccessContext) {
      scontext += "|AccessContext";
    }

    if (scontext != "") {
      scontext = " (" + scontext.substr(1) + ")";
    }

    type = (int)etype;

    if (e->getActualType()) {
      type_info = e->getActualType()->toString();
      if (e->getExpectedType()) {
        type_info += ":" + e->getExpectedType()->toString();
      }
      if (e->getImplementedType()) {
        type_info += ";" + e->getImplementedType()->toString();
      }
      type_info = "{" + type_info + "} ";
    }
  } else {
    ASSERT(FALSE);
  }

  int s = spc;
  while (s > 0) {
    int n = s > 10 ? 10 : s;
    std::cout << ("          "+10-n);
    s -= n;
  }

  std::cout << "-> 0x" << hex << setfill('0') << setw(10) << (int64)this << dec;

  std::cout << " " << name << "(" << type << ") ";
  if (id) {
    std::cout << "id=" << id << " ";
  }
  if (idPtr) {
    std::cout << "idp=0x" <<
      hex << setfill('0') << setw(10) << (int64)idPtr.get() << " ";
  }

  if (value != "") {
    std::cout << "[" << value << "] ";
  }

  string sef;
  if ((ef & UnknownEffect) == UnknownEffect) {
    sef = "|UnknownEffect";
  } else {
    if (ef & IOEffect) sef += "|IOEffect";
    if (ef & AssignEffect) sef += "|AssignEffect";
    if (ef & GlobalEffect) sef += "|GlobalEffect";
    if (ef & LocalEffect) sef += "|LocalEffect";
    if (ef & ParamEffect) sef += "|ParamEffect";
    if (ef & DeepParamEffect) sef += "|DeepParamEffect";
    if (ef & DynamicParamEffect) sef += "|DynamicParamEffect";
    if (ef & CanThrow) sef += "|CanThrow";
    if (ef & AccessorEffect) sef += "|AccessorEffect";
    if (ef & CreateEffect) sef += "|CreateEffect";
    if (ef & DiagnosticEffect) sef += "|DiagnosticEffect";
    if (ef & OtherEffect) sef += "|OtherEffect";
  }
  if (sef != "") {
    sef = " (" + sef.substr(1) + ")";
  }

  std::cout << type_info << nkid << scontext << sef;
  if (m_loc) {
    std::cout << " " << m_loc->file << ":" <<
      m_loc->line1 << "@" << m_loc->char1;
  }
  std::cout << "\n";
}
Example #17
0
void FunctionScope::init(AnalysisResultConstPtr ar) {
  m_dynamicInvoke = false;
  bool canInline = true;
  if (m_pseudoMain) {
    canInline = false;
    m_variables->forceVariants(ar, VariableTable::AnyVars);
    setReturnType(ar, Type::Variant);
  }

  if (m_refReturn) {
    m_returnType = Type::Variant;
  }

  if (!strcasecmp(m_name.c_str(), "__autoload")) {
    setVolatile();
  }

  // FileScope's flags are from parser, but VariableTable has more flags
  // coming from type inference phase. So we are tranferring these flags
  // just for better modularization between FileScope and VariableTable.
  if (m_attribute & FileScope::ContainsDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsLDynamicVariable) {
    m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
  }
  if (m_attribute & FileScope::ContainsExtract) {
    m_variables->setAttribute(VariableTable::ContainsExtract);
  }
  if (m_attribute & FileScope::ContainsCompact) {
    m_variables->setAttribute(VariableTable::ContainsCompact);
  }
  if (m_attribute & FileScope::ContainsUnset) {
    m_variables->setAttribute(VariableTable::ContainsUnset);
  }
  if (m_attribute & FileScope::ContainsGetDefinedVars) {
    m_variables->setAttribute(VariableTable::ContainsGetDefinedVars);
  }

  if (m_stmt && Option::AllVolatile && !m_pseudoMain && !m_method) {
    m_volatile = true;
  }

  m_dynamic = Option::IsDynamicFunction(m_method, m_name) ||
    Option::EnableEval == Option::FullEval || Option::AllDynamic;
  if (!m_method && Option::DynamicInvokeFunctions.find(m_name) !=
      Option::DynamicInvokeFunctions.end()) {
    setDynamicInvoke();
  }
  if (m_modifiers) {
    m_virtual = m_modifiers->isAbstract();
  }

  if (m_stmt) {
    MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
    StatementListPtr stmts = stmt->getStmts();
    if (stmts) {
      if (stmts->getRecursiveCount() > Option::InlineFunctionThreshold)
        canInline = false;
      for (int i = 0; i < stmts->getCount(); i++) {
        StatementPtr stmt = (*stmts)[i];
        stmt->setFileLevel();
        if (stmt->is(Statement::KindOfExpStatement)) {
          ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
          ExpressionPtr exp = expStmt->getExpression();
          exp->setTopLevel();
        }
      }
    }
  } else {
    canInline = false;
  }
  m_inlineable = canInline;
}
Example #18
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::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);
}
Example #19
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();
  }
}
Example #20
0
void ClassVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {

  // bail out early if possible
  switch (cg.getContext()) {
  case CodeGenerator::CppConstructor:
  case CodeGenerator::CppInitializer:
    if (m_modifiers->isStatic()) return;
    break;
  default:
    return;
  }

  ClassScopePtr scope = getClassScope();
  bool derivFromRedec = scope->derivesFromRedeclaring() &&
    !m_modifiers->isPrivate();

  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];
    SimpleVariablePtr var;
    TypePtr type;
    Symbol *sym;
    ExpressionPtr value;

    bool initInCtor = false;
    bool initInInit = false;
    getCtorAndInitInfo(exp, initInCtor, initInInit, var, type, sym, value);

    bool isAssign = exp->is(Expression::KindOfAssignmentExpression);
    bool isValueNull = isAssign ? value->isLiteralNull() : false;

    switch (cg.getContext()) {
    case CodeGenerator::CppConstructor:
      if (initInCtor) {
        if (!cg.hasInitListFirstElem()) {
          cg.setInitListFirstElem();
        } else {
          cg_printf(", ");
        }
        if (isAssign) {
          if (isValueNull) {
            cg_printf("%s%s(%s)",
                      Option::PropertyPrefix, var->getName().c_str(),
                      Type::IsMappedToVariant(type) ? "Variant::nullInit" : "");
          } else {
            assert(value);
            assert(value->is(Expression::KindOfScalarExpression));
            cg_printf("%s%s(",
                      Option::PropertyPrefix,
                      var->getName().c_str());
            value->outputCPP(cg, ar);
            cg_printf(")");
          }
        } else {
          if (type->is(Type::KindOfVariant)) {
            cg_printf("%s%s(Variant::nullInit)",
                      Option::PropertyPrefix,
                      var->getName().c_str());
          } else {
            const char *initializer = type->getCPPInitializer();
            assert(initializer);
            cg_printf("%s%s(%s)",
                      Option::PropertyPrefix,
                      var->getName().c_str(),
                      initializer);
          }
        }
      }
      break;
    case CodeGenerator::CppInitializer:
      if (initInInit) {
        if (isAssign) {
          value->outputCPPBegin(cg, ar);
          if (derivFromRedec) {
            cg_printf("%sset(", Option::ObjectPrefix);
            cg_printString(var->getName(), ar, shared_from_this());
            cg_printf(", ");
            value->outputCPP(cg, ar);
            cg_printf(")");
          } else if (isValueNull) {
            cg_printf("setNull(%s%s)", Option::PropertyPrefix,
                      var->getName().c_str());
          } else {
            cg_printf("%s%s = ", Option::PropertyPrefix, var->getName().c_str());
            value->outputCPP(cg, ar);
          }
          cg_printf(";\n");
          value->outputCPPEnd(cg, ar);
        } else {
          if (derivFromRedec) {
            cg_printf("%sset(", Option::ObjectPrefix);
            cg_printString(var->getName(), ar, shared_from_this());
            cg_printf(", null_variant);\n");
          } else {
            if (type->is(Type::KindOfVariant)) {
              cg_printf("setNull(%s%s);\n", Option::PropertyPrefix,
                        var->getName().c_str());
            } else {
              const char *initializer = type->getCPPInitializer();
              assert(initializer);
              cg_printf("%s%s = %s;\n", Option::PropertyPrefix,
                        var->getName().c_str(), initializer);
            }
          }
        }
      }
      break;
    default:
      break;
    }
  }
}
ReturnStatement::ReturnStatement
(STATEMENT_CONSTRUCTOR_PARAMETERS, ExpressionPtr exp)
  : Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(ReturnStatement)),
    m_exp(exp) {
  if (exp) exp->setContext(Expression::ReturnContext);
}
bool AssignmentExpression::SpecialAssignment(CodeGenerator &cg,
                                             AnalysisResultPtr ar,
                                             ExpressionPtr lval,
                                             ExpressionPtr rval,
                                             const char *rvalStr, bool ref) {
  if (lval->is(KindOfArrayElementExpression)) {
    ArrayElementExpressionPtr exp =
      dynamic_pointer_cast<ArrayElementExpression>(lval);
    if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
      exp->getVariable()->outputCPP(cg, ar);
      if (exp->getOffset()) {
        cg_printf(".set(");
        exp->getOffset()->outputCPP(cg, ar);
        cg_printf(", (");
      } else {
        cg_printf(".append((");
      }
      if (rval) {
        wrapValue(cg, ar, rval, ref,
                  (exp->getVariable()->is(KindOfArrayElementExpression) ||
                   exp->getVariable()->is(KindOfObjectPropertyExpression)) &&
                  (exp->getVariable()->getContainedEffects() &&
                   (CreateEffect|AccessorEffect)), true);
      } else {
        cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
      }
      cg_printf(")");
      ExpressionPtr off = exp->getOffset();
      if (off) {
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(off);
        if (sc) {
          if (sc->isLiteralString()) {
            String s(sc->getLiteralString());
            int64 n;
            if (!s.get()->isStrictlyInteger(n)) {
              cg_printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg_printf(")");
      return true;
    }
  } else if (lval->is(KindOfObjectPropertyExpression)) {
    ObjectPropertyExpressionPtr var(
      dynamic_pointer_cast<ObjectPropertyExpression>(lval));
    if (!var->isValid()) {
      bool nonPrivate = var->isNonPrivate(ar);
      var->outputCPPObject(cg, ar);
      if (nonPrivate) {
        cg_printf("o_setPublic(");
      } else {
        cg_printf("o_set(");
      }
      var->outputCPPProperty(cg, ar);
      cg_printf(", %s", ref ? "ref(" : "");
      if (rval) {
        rval->outputCPP(cg, ar);
      } else {
        cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
      }
      if (nonPrivate) {
        cg_printf("%s)", ref ? ")" : "");
      }
      else {
        cg_printf("%s%s)",
                  ref ? ")" : "",
                  lval->originalClassName(cg, true).c_str());
      }
      return true;
    }
  }
  return false;
}
bool BinaryOpExpression::canonCompare(ExpressionPtr e) const {
  return Expression::canonCompare(e) &&
    getOp() == static_cast<BinaryOpExpression*>(e.get())->getOp();
}
Example #24
0
bool SimpleVariable::canonCompare(ExpressionPtr e) const {
    return Expression::canonCompare(e) &&
           getName() == static_cast<SimpleVariable*>(e.get())->getName();
}
Example #25
0
bool StatementList::mergeConcatAssign(AnalysisResultPtr ar) {
  if (Option::LocalCopyProp) {
    return false;
  } else {
    // check for vector string concat assignment such as
    //   $space = " ";
    //   $a .= "hello";
    //   $a .= $space;
    //   $a .= "world!";
    // turn into (for constant folding and concat sequence)
    //   $a .= " " . "hello " . $space . "world!";
    unsigned int i = 0;
    bool merged = false;
    do {
      std::string lhsName;
      int length = 0;
      for (; i < m_stmts.size(); i++) {
        StatementPtr stmt = m_stmts[i];
        if (!stmt->is(Statement::KindOfExpStatement)) break;
        ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
        ExpressionPtr exp = expStmt->getExpression();

        // check the first assignment
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          AssignmentExpressionPtr assignment_exp =
            dynamic_pointer_cast<AssignmentExpression>(exp);
          ExpressionPtr variable = assignment_exp->getVariable();
          ExpressionPtr value = assignment_exp->getValue();
          std::string variableName = variable->getText();
          if (variableName.find("->") != std::string::npos) break;
          if (value->hasEffect()) break;
          // cannot turn $a .= $b; a .= $a into $a .= $b . $a;
          if (value->getText().find(variableName) != std::string::npos) break;
          if (lhsName.empty()) {
            lhsName = variable->getText();
            length++;
            continue;
          } else {
            break;
          }
        } else if (!exp->is(Expression::KindOfBinaryOpExpression)) {
          break;
        }
        BinaryOpExpressionPtr binaryOpExp =
          dynamic_pointer_cast<BinaryOpExpression>(exp);
        if (binaryOpExp->getOp() != T_CONCAT_EQUAL) break;
        ExpressionPtr exp1 = binaryOpExp->getExp1();
        std::string exp1Text = exp1->getText();
        if (exp1Text.find("->") != std::string::npos) break;
        ExpressionPtr exp2 = binaryOpExp->getExp2();
        if (exp2->hasEffect()) break;
        if (exp2->getText().find(exp1Text) != std::string::npos) break;
        if (lhsName.empty()) {
          lhsName = exp1Text;
          length++;
        } else if (lhsName == exp1Text) {
          length++;
        } else {
          break;
        }
      }
      if (length > 1) {
        // replace m_stmts[j] to m_stmts[i - 1] with a new statement
        unsigned j = i - length;
        ExpStatementPtr expStmt;
        ExpressionPtr exp;
        BinaryOpExpressionPtr binaryOpExp;
        ExpressionPtr var;
        ExpressionPtr exp1;
        ExpressionPtr exp2;
        bool isAssignment = false;
        expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j++]);
        exp = expStmt->getExpression();
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          isAssignment = true;
          AssignmentExpressionPtr assignment_exp =
            dynamic_pointer_cast<AssignmentExpression>(exp);
          var = assignment_exp->getVariable();
          exp1 = assignment_exp->getValue();
        } else {
          binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
          var = binaryOpExp->getExp1();
          exp1 = binaryOpExp->getExp2();
        }

        for (; j < i; j++) {
          expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j]);
          exp = expStmt->getExpression();
          binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
          exp2 = binaryOpExp->getExp2();
          exp1 = BinaryOpExpressionPtr
            (new BinaryOpExpression(getLocation(),
                                    Expression::KindOfBinaryOpExpression,
                                    exp1, exp2, '.'));
        }
        if (isAssignment) {
          exp = AssignmentExpressionPtr
            (new AssignmentExpression(exp->getLocation(),
                                      Expression::KindOfAssignmentExpression,
                                      var, exp1,
                                      false));
        } else {
          exp = BinaryOpExpressionPtr
            (new BinaryOpExpression(getLocation(),
                                    Expression::KindOfBinaryOpExpression,
                                    var, exp1, T_CONCAT_EQUAL));
        }
        expStmt = ExpStatementPtr
          (new ExpStatement(getLocation(),
                            Statement::KindOfExpStatement, exp));

        m_stmts[i - length] = expStmt;
        for (j = i - (length - 1); i > j; i--) removeElement(j);
        merged = true;
      } else if (length == 0) {
        i++;
      }
    } while (i < m_stmts.size());
    return merged;
  }
}
Example #26
0
void Dictionary::record(ExpressionPtr e) {
    e->setCanonID(m_idMap.size());
    m_idMap.push_back(e);
}
Example #27
0
void ExprDict::visit(ExpressionPtr e) {
  assert(m_canonIdMap.size() == m_canonTypeMap.size());
  if (m_am.insertForDict(e)) {
    // we've never seen e's structure before, so record it
    record(e);
    if (e->getCanonID() >= m_canonTypeMap.size()) {
      m_canonTypeMap.resize(e->getCanonID() + 1);
      m_canonIdMap.resize(e->getCanonID() + 1);
    }
    m_canonTypeMap[e->getCanonID()] =
      TypePtrIdxPair(extractTypeAssertion(e), e->getCanonID());
    m_canonIdMap[e->getCanonID()] = e->getCanonID();
  } else if (e->isTypeAssertion()) {
    TypePtrIdxPairVec types;
    assert(isCanonicalStructure(e->getCanonID()));
    getTypes(e->getCanonID(), types);
    TypePtrIdxPair entry;
    if (containsAssertion(e->getAssertedType(), types, entry)) {
      e->setCanonID(entry.second);
    } else {
      // new type assertion seen, record it
      int oldId = e->getCanonID();
      assert(isCanonicalStructure(oldId));
      record(e);
      // insert it into the list
      if (e->getCanonID() >= m_canonTypeMap.size()) {
        m_canonTypeMap.resize(e->getCanonID() + 1);
        m_canonIdMap.resize(e->getCanonID() + 1);
      }
      m_canonIdMap[e->getCanonID()] = oldId;
      TypePtrIdxPair &head = m_canonTypeMap[oldId];
      int oldSecond = head.second;
      head.second = e->getCanonID();
      m_canonTypeMap[e->getCanonID()] =
        TypePtrIdxPair(e->getAssertedType(), oldSecond);
    }
  }
}
Example #28
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);
}
Example #29
0
ExpressionPtr ExprDict::propagate(ExpressionPtr e) {
  return m_avlExpr[e->getCanonID()];
}
void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
    if (m_class) {
        m_class->analyzeProgram(ar);
        setDynamicByIdentifier(ar, m_name);
    } else {
        if (m_className.empty()) {
            addUserFunction(ar, m_name);
        } else if (m_className != "parent") {
            addUserClass(ar, m_className);
        } else {
            m_parentClass = true;
        }
    }

    if (ar->getPhase() == AnalysisResult::AnalyzeInclude) {

        CHECK_HOOK(onSimpleFunctionCallAnalyzeInclude);

        ConstructPtr self = shared_from_this();

        // We need to know the name of the constant so that we can associate it
        // with this file before we do type inference.
        if (!m_class && m_className.empty() && m_type == DefineFunction) {
            ScalarExpressionPtr name =
                dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
            string varName;
            if (name) {
                varName = name->getIdentifier();
                if (!varName.empty()) {
                    ar->getFileScope()->declareConstant(ar, varName);
                }
            }
            // handling define("CONSTANT", ...);
            if (m_params && m_params->getCount() >= 2) {
                ScalarExpressionPtr name =
                    dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
                string varName;
                if (name) {
                    varName = name->getIdentifier();
                    if (!varName.empty()) {
                        ExpressionPtr value = (*m_params)[1];
                        ConstantTablePtr constants =
                            ar->findConstantDeclarer(varName)->getConstants();
                        if (constants != ar->getConstants()) {
                            constants->add(varName, NEW_TYPE(Some), value, ar, self);

                            if (name->hasHphpNote("Dynamic")) {
                                constants->setDynamic(ar, varName);
                            }
                        }
                    }
                }
            }
        }

        if (m_type == UnserializeFunction) {
            ar->forceClassVariants();
        }
    }

    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
        // Look up the corresponding FunctionScope and ClassScope
        // for this function call
        {
            FunctionScopePtr func;
            ClassScopePtr cls;
            if (!m_class && m_className.empty()) {
                func = ar->findFunction(m_name);
            } else {
                cls = ar->resolveClass(m_className);
                if (cls) {
                    if (m_name == "__construct") {
                        func = cls->findConstructor(ar, true);
                    } else {
                        func = cls->findFunction(ar, m_name, true, true);
                    }
                }
            }
            if (func && !func->isRedeclaring()) {
                if (m_funcScope != func) {
                    m_funcScope = func;
                    Construct::recomputeEffects();
                }
            }
            if (cls && !cls->isRedeclaring())
                m_classScope = cls;
        }
        // check for dynamic constant and volatile function/class
        if (!m_class && m_className.empty() &&
                (m_type == DefinedFunction ||
                 m_type == FunctionExistsFunction ||
                 m_type == ClassExistsFunction ||
                 m_type == InterfaceExistsFunction) &&
                m_params && m_params->getCount() >= 1) {
            ExpressionPtr value = (*m_params)[0];
            if (value->isScalar()) {
                ScalarExpressionPtr name =
                    dynamic_pointer_cast<ScalarExpression>(value);
                if (name && name->isLiteralString()) {
                    string symbol = name->getLiteralString();
                    switch (m_type) {
                    case DefinedFunction: {
                        ConstantTablePtr constants = ar->getConstants();
                        if (!constants->isPresent(symbol)) {
                            // user constant
                            BlockScopePtr block = ar->findConstantDeclarer(symbol);
                            if (block) { // found the constant
                                constants = block->getConstants();
                                // set to be dynamic
                                constants->setDynamic(ar, symbol);
                            }
                        }
                        break;
                    }
                    case FunctionExistsFunction: {
                        FunctionScopePtr func = ar->findFunction(Util::toLower(symbol));
                        if (func && func->isUserFunction()) {
                            func->setVolatile();
                        }
                        break;
                    }
                    case InterfaceExistsFunction:
                    case ClassExistsFunction: {
                        ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
                        if (cls && cls->isUserClass()) {
                            cls->setVolatile();
                        }
                        break;
                    }
                    default:
                        ASSERT(false);
                    }
                }
            }
        }
    }

    if (m_params) {
        if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
            if (m_funcScope) {
                ExpressionList &params = *m_params;
                int mpc = m_funcScope->getMaxParamCount();
                for (int i = params.getCount(); i--; ) {
                    ExpressionPtr p = params[i];
                    if (i < mpc ? m_funcScope->isRefParam(i) :
                            m_funcScope->isReferenceVariableArgument()) {
                        p->setContext(Expression::RefValue);
                    } else if (!(p->getContext() & Expression::RefParameter)) {
                        p->clearContext(Expression::RefValue);
                    }
                }
            } else {
                FunctionScopePtr func = ar->findFunction(m_name);
                if (func && func->isRedeclaring()) {
                    FunctionScope::RefParamInfoPtr info =
                        FunctionScope::GetRefParamInfo(m_name);
                    if (info) {
                        for (int i = m_params->getCount(); i--; ) {
                            if (info->isRefParam(i)) {
                                m_params->markParam(i, canInvokeFewArgs());
                            }
                        }
                    }
                } else {
                    m_params->markParams(false);
                }
            }
        }

        m_params->analyzeProgram(ar);
    }
}