コード例 #1
0
void GlobalStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  if (m_dynamicGlobal) {
    cg_printf("throw_fatal(\"dynamic global\");\n");
  } else {
    BlockScopePtr scope = ar->getScope();
    if (m_exp->getCount() > 1) cg_indentBegin("{\n");
    for (int i = 0; i < m_exp->getCount(); i++) {
      ExpressionPtr exp = (*m_exp)[i];
      if (exp->is(Expression::KindOfSimpleVariable)) {
        SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp);
        const string &name = var->getName();
        VariableTablePtr variables = scope->getVariables();
        if (variables->needLocalCopy(name)) {
          cg_printf("%s%s = ref(g->%s);\n",
                    Option::VariablePrefix, name.c_str(),
                    variables->getGlobalVariableName(ar, name).c_str());
        }
      }
      else {
        // type inference should have set m_dynamicGlobal to true.
        ASSERT(false);
      }
    }
    if (m_exp->getCount() > 1) cg_indentEnd("}\n");
  }
}
コード例 #2
0
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar,
                                        ClassScopePtr scope) {
  // This is that much we can do during parse phase.
  TypePtr type;
  if (m_value->is(Expression::KindOfScalarExpression)) {
    type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl(
      ar, Type::Some, false);
  } else if (m_value->is(Expression::KindOfUnaryOpExpression)) {
    UnaryOpExpressionPtr uexp =
      dynamic_pointer_cast<UnaryOpExpression>(m_value);
    if (uexp->getOp() == T_ARRAY) {
      type = Type::Array;
    }
  }
  if (!type) type = Type::Some;

  if (m_variable->is(Expression::KindOfConstantExpression)) {
    // ...as in ClassConstant statement
    // We are handling this one here, not in ClassConstant, purely because
    // we need "value" to store in constant table.
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(m_variable);
    scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable);
  } else if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable);
    scope->getVariables()->add(var->getName(), type, true, ar,
                               shared_from_this(), scope->getModifiers());
    var->clearContext(Declaration); // to avoid wrong CodeError
  } else {
    ASSERT(false); // parse phase shouldn't handle anything else
  }
}
コード例 #3
0
ArrayElementExpression::ArrayElementExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
 ExpressionPtr variable, ExpressionPtr offset)
  : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ArrayElementExpression)),
    LocalEffectsContainer(AccessorEffect),
    m_variable(variable), m_offset(offset), m_global(false),
    m_dynamicGlobal(false) {
  m_variable->setContext(Expression::AccessContext);

  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      m_global = true;
      m_dynamicGlobal = true;
      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
          }
        }
      }
    }
  }
}
コード例 #4
0
void ClassVariable::getCtorAndInitInfo(
    ExpressionPtr exp,
    bool &needsCppCtor,
    bool &needsInit,
    SimpleVariablePtr &var,
    TypePtr &type,
    Symbol *&sym,
    ExpressionPtr &value) {

  ClassScopePtr scope = getClassScope();
  bool derivFromRedec = scope->derivesFromRedeclaring() &&
    !m_modifiers->isPrivate();
  AssignmentExpressionPtr assignment;
  bool isAssign = exp->is(Expression::KindOfAssignmentExpression);
  if (isAssign) {
    assignment = static_pointer_cast<AssignmentExpression>(exp);
    var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
    ASSERT(var);
    value = assignment->getValue();
    ASSERT(value);
  } else {
    var = dynamic_pointer_cast<SimpleVariable>(exp);
    ASSERT(var);
  }
  sym = scope->getVariables()->getSymbol(var->getName());
  ASSERT(sym);
  type = scope->getVariables()->getFinalType(var->getName());
  ASSERT(type);

  bool isValueNull = isAssign ? value->isLiteralNull() : false;
  bool typeIsInitable = type->is(Type::KindOfVariant) ||
                        type->getCPPInitializer();
  if (!derivFromRedec &&
      !sym->isOverride() &&
      (isAssign ?
        (isValueNull ||
         (value->is(Expression::KindOfScalarExpression) &&
          type->isPrimitive())) :
        typeIsInitable)) {
    needsCppCtor = true;
  } else if (isAssign || typeIsInitable) {
    // if we aren't an assignment and the type is not a variant
    // w/ no CPP initializer, then we currently don't bother
    // to initialize it in init().
    needsInit = true;
  }
}
コード例 #5
0
ファイル: capture_extractor.cpp プロジェクト: shuc324/hhvm
/**
 * If a simple variable refers to a name bound inside the query
 * then leave it alone. If not, rewrite it to be reference to
 * a query parameter.
 */
SimpleVariablePtr CaptureExtractor::rewriteSimpleVariable(
  SimpleVariablePtr sv) {
  assert(sv != nullptr);
  auto varName = sv->getName();
  for (auto &boundVar : m_boundVars) {
    if (varName == boundVar) return sv;
  }
  return newQueryParamRef(sv);
}
コード例 #6
0
void ExpressionList::optimize(AnalysisResultConstPtr ar) {
  bool changed = false;
  size_t i = m_exps.size();
  if (m_kind != ListKindParam) {
    size_t skip = m_kind == ListKindLeft ? 0 : i - 1;
    while (i--) {
      if (i != skip) {
        ExpressionPtr &e = m_exps[i];
        if (!e || e->getContainedEffects() == NoEffect) {
          removeElement(i);
          changed = true;
        } else if (e->is(KindOfExpressionList)) {
          ExpressionListPtr el(static_pointer_cast<ExpressionList>(e));
          removeElement(i);
          for (size_t j = el->getCount(); j--; ) {
            insertElement((*el)[j], i);
          }
          changed = true;
        } else if (e->getLocalEffects() == NoEffect) {
          e = e->unneeded();
          // changed already handled by unneeded
        }
      }
    }
    if (m_exps.size() == 1) {
      m_kind = ListKindWrapped;
    } else if (m_kind == ListKindLeft && m_exps[0]->isScalar()) {
      ExpressionPtr e = m_exps[0];
      removeElement(0);
      addElement(e);
      m_kind = ListKindWrapped;
    }
  } else {
    if (hasContext(UnsetContext) &&
        ar->getPhase() >= AnalysisResult::PostOptimize) {
      while (i--) {
        ExpressionPtr &e = m_exps[i];
        if (e->is(Expression::KindOfSimpleVariable)) {
          SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(e);
          if (var->checkUnused()) {
            const std::string &name = var->getName();
            VariableTablePtr variables = getScope()->getVariables();
            if (!variables->isNeeded(name)) {
              removeElement(i);
              changed = true;
            }
          }
        }
      }
    }
  }
  if (changed) {
    getScope()->addUpdates(BlockScope::UseKindCaller);
  }
}
コード例 #7
0
void ClassVariable::inferTypes(AnalysisResultPtr ar) {
  m_declaration->inferAndCheck(ar, NEW_TYPE(Some), false);

  if (m_modifiers->isStatic()) {
    ClassScopePtr scope = ar->getClassScope();
    for (int i = 0; i < m_declaration->getCount(); i++) {
      ExpressionPtr exp = (*m_declaration)[i];
      if (exp->is(Expression::KindOfAssignmentExpression)) {
        scope->setNeedStaticInitializer();
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        // If the class variable's type is Object, we have to
        // force it to be a Variant, because we don't include
        // the class header files in global_variables.h
        SimpleVariablePtr var =
          dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        if (var) {
          TypePtr type = scope->getVariables()->getFinalType(var->getName());
          if (type->is(Type::KindOfObject)) {
            scope->getVariables()->forceVariant(ar, var->getName());
          }
        }
        ExpressionPtr value = assignment->getValue();
        if (value->containsDynamicConstant(ar)) {
          scope->getVariables()->
            setAttribute(VariableTable::ContainsDynamicStatic);
        }
      } else {
        SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp);
        TypePtr type = scope->getVariables()->getFinalType(var->getName());
        // If the class variable's type is Object, we have to
        // force it to be a Variant, because we don't include
        // the class header files in global_variables.h
        if (type->is(Type::KindOfObject)) {
          scope->getVariables()->forceVariant(ar, var->getName());
        }
        const char *initializer = type->getCPPInitializer();
        if (initializer) scope->setNeedStaticInitializer();
      }
    }
  }
}
コード例 #8
0
void GlobalStatement::inferTypes(AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  scope->getVariables()->setAttribute(VariableTable::InsideGlobalStatement);
  for (int i = 0; i < m_exp->getCount(); i++) {
    ExpressionPtr exp = (*m_exp)[i];
    if (exp->is(Expression::KindOfSimpleVariable)) {
      SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp);
      VariableTablePtr variables = scope->getVariables();
      const std::string &name = var->getName();
      /* If we have already seen this variable in the current scope and
         it is not a global variable, record this variable as "redeclared"
         which will force Variant type.
       */
      variables->checkRedeclared(name, KindOfGlobalStatement);
      variables->addLocalGlobal(name);
      var->setContext(Expression::Declaration);
      var->inferAndCheck(ar, NEW_TYPE(Any), true);
      variables->forceVariant(ar, name);
      variables->setAttribute(VariableTable::NeedGlobalPointer);

      ConstructPtr decl =
        ar->getVariables()->getDeclaration(var->getName());
      if (decl) {
        ar->getDependencyGraph()->add(DependencyGraph::KindOfGlobalVariable,
                                      ar->getName(),
                                      var->getName(), var,
                                      var->getName(), decl);
      }
    } else {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(shared_from_this(),
                                   CodeError::UseDynamicGlobal, exp);
      }
      m_dynamicGlobal = true;
    }
  }
  FunctionScopePtr func = ar->getFunctionScope();
  scope->getVariables()->clearAttribute(VariableTable::InsideGlobalStatement);
}
コード例 #9
0
void StaticStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  BlockScopePtr scope = getScope();
  if (scope->inPseudoMain()) {
    if (m_exp->getCount() > 1) cg_indentBegin("{\n");
    for (int i = 0; i < m_exp->getCount(); i++) {
      ExpressionPtr exp = (*m_exp)[i];
      if (exp->is(Expression::KindOfAssignmentExpression)) {
        exp->outputCPP(cg, ar);
        cg_printf(";\n");
      } else {
        ASSERT(false);
      }
    }
    if (m_exp->getCount() > 1) cg_indentEnd("}\n");
    return;
  }

  VariableTablePtr variables = scope->getVariables();
  if (m_exp->getCount() > 1) cg_indentBegin("{\n");
  for (int i = 0; i < m_exp->getCount(); i++) {
    ExpressionPtr exp = (*m_exp)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment_exp =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr variable = assignment_exp->getVariable();
      SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
      assert(var->hasContext(Expression::Declaration));
      const std::string &name = var->getName();

      if (variables->needLocalCopy(name)) {
        ASSERT(var->hasAssignableCPPVariable());
        cg_printf("%s.assignRef(%s%s);\n",
                  var->getAssignableCPPVariable(ar).c_str(),
                  Option::StaticVariablePrefix, name.c_str());
      }

      cg_indentBegin("if (!%s%s%s) {\n", Option::InitPrefix,
                     Option::StaticVariablePrefix, name.c_str());
      exp->outputCPP(cg, ar);
      cg_printf(";\n");
      cg_printf("%s%s%s = true;\n", Option::InitPrefix,
                Option::StaticVariablePrefix, name.c_str());
      cg_indentEnd("}\n");
    } else {
      ASSERT(false);
    }
  }
  if (m_exp->getCount() > 1) cg_indentEnd("}\n");
}
コード例 #10
0
StatementPtr ClassVariable::preOptimize(AnalysisResultConstPtr ar) {
  ClassScopePtr scope = getClassScope();
  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      ExpressionPtr value = assignment->getValue();
      scope->getVariables()->setClassInitVal(var->getName(), value);
    }
  }
  return StatementPtr();
}
コード例 #11
0
void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) {
  m_declaration->analyzeProgram(ar);
  if (ar->getPhase() != AnalysisResult::AnalyzeInclude) return;
  ClassScopePtr scope = ar->getClassScope();
  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      ExpressionPtr value = assignment->getValue();
      scope->getVariables()->setClassInitVal(var->getName(), value);
    }
  }
}
コード例 #12
0
ファイル: expression.cpp プロジェクト: andyanx/hhvm
bool Expression::CheckNeeded(ExpressionPtr variable, ExpressionPtr value) {
  // if the value may involve object, consider the variable as "needed"
  // so that objects are not destructed prematurely.
  bool needed = true;
  if (value) needed = CheckNeededRHS(value);
  if (variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(variable);
    const std::string &name = var->getName();
    VariableTablePtr variables = var->getScope()->getVariables();
    if (needed) {
      variables->addNeeded(name);
    } else {
      needed = variables->isNeeded(name);
    }
  }
  return needed;
}
コード例 #13
0
ExpressionPtr AssignmentExpression::postOptimize(AnalysisResultPtr ar) {
  ar->postOptimize(m_variable);
  ar->postOptimize(m_value);
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    const std::string &name = var->getName();
    VariableTablePtr variables = ar->getScope()->getVariables();
    if (variables->checkUnused(name)) {
      variables->addUnused(name);
      if (m_value->getContainedEffects() != getContainedEffects()) {
        s_effectsTag++;
      }
      return m_value;
    }
  }
  return ExpressionPtr();
}
コード例 #14
0
void ClassVariable::addTraitPropsToScope(AnalysisResultPtr ar,
                                         ClassScopePtr scope) {
  ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers);
  VariableTablePtr variables = scope->getVariables();

  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];

    SimpleVariablePtr var;
    ExpressionPtr value;
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      value = assignment->getValue();
    } else {
      var = dynamic_pointer_cast<SimpleVariable>(exp);
      value = makeConstant(ar, "null");
    }

    const string &name = var->getName();
    Symbol *sym;
    ClassScopePtr prevScope = variables->isPresent(name) ? scope :
      scope->getVariables()->findParent(ar, name, sym);

    if (prevScope &&
        !isEquivRedecl(name, exp, m_modifiers,
                       prevScope->getVariables()->getSymbol(name))) {
      Compiler::Error(Compiler::DeclaredVariableTwice, exp);
      m_declaration->removeElement(i--);
    } else {
      if (prevScope != scope) { // Property is new or override, so add it
        variables->add(name, Type::Variant, false, ar, exp, m_modifiers);
        variables->getSymbol(name)->setValue(exp);
        variables->setClassInitVal(name, value);
        variables->markOverride(ar, name);
      } else {
        m_declaration->removeElement(i--);
      }
    }
  }
  scope->setModifiers(modifiers);
}
コード例 #15
0
void AssignmentExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_variable->analyzeProgram(ar);
  m_value->analyzeProgram(ar);
  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    if (m_ref && m_variable->is(Expression::KindOfSimpleVariable)) {
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(m_variable);
      const std::string &name = var->getName();
      VariableTablePtr variables = ar->getScope()->getVariables();
      variables->addUsed(name);
    }
    if (m_variable->is(Expression::KindOfConstantExpression)) {
      ConstantExpressionPtr exp =
        dynamic_pointer_cast<ConstantExpression>(m_variable);
      if (!m_value->isScalar()) {
        ar->getScope()->getConstants()->setDynamic(ar, exp->getName());
      }
    }
  }
}
コード例 #16
0
void ArrayElementExpression::setContext(Context context) {
  m_context |= context;
  if (context == Expression::LValue) {
    m_variable->setContext(Expression::LValue);
    if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
      m_variable->clearContext(Expression::NoLValueWrapper);
    }
    // special case for $GLOBALS[], see the if (m_global) check in
    // ArrayElementExpression::outputCPPImpl, we do not need lvalue wrapper
    if (m_variable->is(Expression::KindOfSimpleVariable)) {
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(m_variable);
      if (var->getName() == "GLOBALS") {
        m_context |= Expression::NoLValueWrapper;
      }
    }
  } else if (context == Expression::DeepAssignmentLHS ||
             context == Expression::ExistContext ||
             context == Expression::UnsetContext) {
    m_variable->setContext(context);
  }
}
コード例 #17
0
void ArrayElementExpression::setContext(Context context) {
  m_context |= context;
  switch (context) {
    case Expression::LValue:
      if (!hasContext(Expression::UnsetContext)) {
        m_variable->setContext(Expression::LValue);
      }
      if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
        m_variable->clearContext(Expression::NoLValueWrapper);
      }
      // special case for $GLOBALS[], see the if (m_global) check in
      // ArrayElementExpression::outputCPPImpl, we do not need lvalue wrapper
      if (m_variable->is(Expression::KindOfSimpleVariable)) {
        SimpleVariablePtr var =
          dynamic_pointer_cast<SimpleVariable>(m_variable);
        if (var->getName() == "GLOBALS") {
          m_context |= Expression::NoLValueWrapper;
        }
      }
      break;
    case Expression::DeepAssignmentLHS:
    case Expression::DeepOprLValue:
    case Expression::ExistContext:
    case Expression::UnsetContext:
    case Expression::DeepReference:
      m_variable->setContext(context);
      break;
    case Expression::RefValue:
    case Expression::RefParameter:
      m_variable->setContext(DeepReference);
      break;
    case Expression::InvokeArgument:
      m_variable->setContext(context);
      setContext(NoLValueWrapper);
    default:
      break;
  }
}
コード例 #18
0
ExpressionPtr AssignmentExpression::postOptimize(AnalysisResultPtr ar) {
  ar->postOptimize(m_variable);
  ar->postOptimize(m_value);
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    const std::string &name = var->getName();
    VariableTablePtr variables = ar->getScope()->getVariables();
    if (!variables->isPseudoMainTable() &&
        !variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
        !variables->isReferenced(name) &&
        variables->isLocal(name)) {
      variables->addUnused(name);
      if (m_value->isScalar()) {
        m_value->setExpectedType(m_expectedType);
        return m_value;
      } else {
        return makeIdCall(ar);
      }
    }
  }
  return ExpressionPtr();
}
コード例 #19
0
bool ObjectPropertyExpression::directVariantProxy(AnalysisResultPtr ar) {
  TypePtr actualType = m_object->getActualType();
  if (actualType && actualType->is(Type::KindOfVariant)) {
    if (m_object->is(KindOfSimpleVariable)) {
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(m_object);
      const std::string &name = var->getName();
      FunctionScopePtr func =
        dynamic_pointer_cast<FunctionScope>(ar->getScope());
      VariableTablePtr variables = func->getVariables();
      if (!variables->isParameter(name) || variables->isLvalParam(name)) {
        return true;
      }
      if (variables->getAttribute(VariableTable::ContainsDynamicVariable) ||
          variables->getAttribute(VariableTable::ContainsExtract)) {
        return true;
      }
    } else {
      return true;
    }
  }
  return false;
}
コード例 #20
0
bool ExpressionList::optimize(AnalysisResultPtr ar) {
  bool changed = false;
  size_t i = m_exps.size();
  if (m_kind != ListKindParam) {
    if (i--) {
      while (i--) {
        ExpressionPtr &e = m_exps[i];
        if (!e || e->getContainedEffects() == NoEffect) {
          ar->incOptCounter();
          removeElement(i);
          changed = true;
        } else if (e->getLocalEffects() == NoEffect) {
          e = e->unneeded(ar);
          changed = true;
        }
      }
    }
    return changed;
  }

  if (hasContext(UnsetContext) &&
      ar->getPhase() >= AnalysisResult::PostOptimize) {
    while (i--) {
      ExpressionPtr &e = m_exps[i];
      if (e->is(Expression::KindOfSimpleVariable)) {
        SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(e);
        const std::string &name = var->getName();
        VariableTablePtr variables = ar->getScope()->getVariables();
        if (variables->checkUnused(name)) {
          removeElement(i);
          changed = true;
        }
      }
    }
  }
  return changed;
}
コード例 #21
0
ExpressionPtr FunctionCall::inliner(AnalysisResultConstPtr ar,
                                    ExpressionPtr obj, std::string localThis) {
  FunctionScopePtr fs = getFunctionScope();
  if (m_noInline || !fs || fs == m_funcScope || !m_funcScope->getStmt()) {
    return ExpressionPtr();
  }

  BlockScope::s_jobStateMutex.lock();
  if (m_funcScope->getMark() == BlockScope::MarkProcessing) {
    fs->setForceRerun(true);
    BlockScope::s_jobStateMutex.unlock();
    return ExpressionPtr();
  }
  ReadLock lock(m_funcScope->getInlineMutex());
  BlockScope::s_jobStateMutex.unlock();

  if (!m_funcScope->getInlineAsExpr()) {
    return ExpressionPtr();
  }

  if (m_funcScope->getInlineSameContext() &&
      m_funcScope->getContainingClass() &&
      m_funcScope->getContainingClass() != getClassScope()) {
    /*
      The function contains a context sensitive construct such as
      call_user_func (context sensitive because it could call
      array('parent', 'foo')) so its not safe to inline it
      into a different context.
    */
    return ExpressionPtr();
  }

  MethodStatementPtr m
    (dynamic_pointer_cast<MethodStatement>(m_funcScope->getStmt()));

  VariableTablePtr vt = fs->getVariables();
  int nAct = m_params ? m_params->getCount() : 0;
  int nMax = m_funcScope->getMaxParamCount();
  if (nAct < m_funcScope->getMinParamCount() || !m->getStmts()) {
    return ExpressionPtr();
  }

  InlineCloneInfo info(m_funcScope);
  info.elist = ExpressionListPtr(new ExpressionList(
                                   getScope(), getLocation(),
                                   ExpressionList::ListKindWrapped));
  std::ostringstream oss;
  oss << fs->nextInlineIndex() << "_" << m_name << "_";
  std::string prefix = oss.str();

  if (obj) {
    info.callWithThis = true;
    if (!obj->isThis()) {
      SimpleVariablePtr var
        (new SimpleVariable(getScope(),
                            obj->getLocation(),
                            prefix + "this"));
      var->updateSymbol(SimpleVariablePtr());
      var->getSymbol()->setHidden();
      var->getSymbol()->setUsed();
      var->getSymbol()->setReferenced();
      AssignmentExpressionPtr ae
        (new AssignmentExpression(getScope(),
                                  obj->getLocation(),
                                  var, obj, false));
      info.elist->addElement(ae);
      info.sepm[var->getName()] = var;
      info.localThis = var->getName();
    }
  } else {
    if (m_classScope) {
      if (!m_funcScope->isStatic()) {
        ClassScopeRawPtr oCls = getOriginalClass();
        FunctionScopeRawPtr oFunc = getOriginalFunction();
        if (oCls && !oFunc->isStatic() &&
            (oCls == m_classScope ||
             oCls->derivesFrom(ar, m_className, true, false))) {
          info.callWithThis = true;
          info.localThis = localThis;
        }
      }
      if (!isSelf() && !isParent() && !isStatic()) {
        info.staticClass = m_className;
      }
    }
  }

  ExpressionListPtr plist = m->getParams();

  int i;

  for (i = 0; i < nMax || i < nAct; i++) {
    ParameterExpressionPtr param
      (i < nMax ?
       dynamic_pointer_cast<ParameterExpression>((*plist)[i]) :
       ParameterExpressionPtr());
    ExpressionPtr arg = i < nAct ? (*m_params)[i] :
      Clone(param->defaultValue(), getScope());
    SimpleVariablePtr var
      (new SimpleVariable(getScope(),
                          (i < nAct ? arg.get() : this)->getLocation(),
                          prefix + (param ?
                                    param->getName() :
                                    lexical_cast<string>(i))));
    var->updateSymbol(SimpleVariablePtr());
    var->getSymbol()->setHidden();
    var->getSymbol()->setUsed();
    var->getSymbol()->setReferenced();
    bool ref =
      (i < nMax && m_funcScope->isRefParam(i)) ||
      arg->hasContext(RefParameter);
    arg->clearContext(RefParameter);
    AssignmentExpressionPtr ae
      (new AssignmentExpression(getScope(),
                                arg->getLocation(),
                                var, arg, ref));
    info.elist->addElement(ae);
    if (i < nAct && (ref || !arg->isScalar())) {
      info.sepm[var->getName()] = var;
    }
  }

  if (cloneStmtsForInline(info, m->getStmts(), prefix, ar,
                          getFunctionScope()) <= 0) {
    info.elist->addElement(makeConstant(ar, "null"));
  }

  if (info.sepm.size()) {
    ExpressionListPtr unset_list
      (new ExpressionList(getScope(), getLocation()));

    for (StringToExpressionPtrMap::iterator it = info.sepm.begin(),
           end = info.sepm.end(); it != end; ++it) {
      ExpressionPtr var = it->second->clone();
      var->clearContext((Context)(unsigned)-1);
      unset_list->addElement(var);
    }

    ExpressionPtr unset(
      new UnaryOpExpression(getScope(), getLocation(),
                            unset_list, T_UNSET, true));
    i = info.elist->getCount();
    ExpressionPtr ret = (*info.elist)[--i];
    if (ret->isScalar()) {
      info.elist->insertElement(unset, i);
    } else {
      ExpressionListPtr result_list
        (new ExpressionList(getScope(), getLocation(),
                            ExpressionList::ListKindLeft));
      if (ret->hasContext(LValue)) {
        result_list->setContext(LValue);
        result_list->setContext(ReturnContext);
      }
      result_list->addElement(ret);
      result_list->addElement(unset);
      (*info.elist)[i] = result_list;
    }
  }

  recomputeEffects();

  return replaceValue(info.elist);
}
コード例 #22
0
TypePtr UnaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
    TypePtr et; // expected m_exp's type
    TypePtr rt; // return type

    switch (m_op) {
    case '!':
        et = rt = Type::Boolean;
        break;
    case '+':
    case '-':
        et = NEW_TYPE(Numeric);
        rt = NEW_TYPE(Numeric);
        break;
    case T_INC:
    case T_DEC:
    case '~':
        et = rt = NEW_TYPE(Primitive);
        break;
    case T_CLONE:
        et = rt = NEW_TYPE(Object);
        break;
    case '@':
        et = type;
        rt = Type::Variant;
        break;
    case '(':
        et = rt = type;
        break;
    case T_INT_CAST:
        et = rt = Type::Int64;
        break;
    case T_DOUBLE_CAST:
        et = rt = Type::Double;
        break;
    case T_STRING_CAST:
        et = rt = Type::String;
        break;
    case T_ARRAY:
        et = NEW_TYPE(Some);
        rt = Type::Array;
        break;
    case T_ARRAY_CAST:
        et = rt = Type::Array;
        break;
    case T_OBJECT_CAST:
        et = rt = NEW_TYPE(Object);
        break;
    case T_BOOL_CAST:
        et = rt = Type::Boolean;
        break;
    case T_UNSET_CAST:
        et = NEW_TYPE(Some);
        rt = Type::Variant;
        break;
    case T_EXIT:
        et = NEW_TYPE(Primitive);
        rt = Type::Variant;
        break;
    case T_PRINT:
        et = Type::String;
        rt = Type::Boolean;
        break;
    case T_ISSET:
        et = Type::Variant;
        rt = Type::Boolean;
        setExistContext();
        break;
    case T_EMPTY:
        et = NEW_TYPE(Some);
        rt = Type::Boolean;
        setExistContext();
        break;
    case T_INCLUDE:
    case T_INCLUDE_ONCE:
    case T_REQUIRE:
    case T_REQUIRE_ONCE:
        et = Type::String;
        rt = Type::Variant;
        break;
    case T_EVAL:
        et = Type::String;
        rt = NEW_TYPE(Any);
        ar->getScope()->getVariables()->forceVariants(ar);
        break;
    case T_FILE:
        et = rt = Type::String;
        break;
    default:
        ASSERT(false);
    }

    if (m_exp) {
        bool ecoerce = false; // expected type needs m_exp to coerce to
        switch (m_op) {
        case T_CLONE:
        case T_ISSET:
            ecoerce = true;
        default:
            break;
        }

        TypePtr expType = m_exp->inferAndCheck(ar, et, ecoerce);
        if (Type::SameType(expType, Type::String) &&
                (m_op == T_INC || m_op == T_DEC)) {
            rt = expType = m_exp->inferAndCheck(ar, Type::Variant, true);
        }

        switch (m_op) {
        case '(':
            /*
              Need to make sure that type conversion happens at the right point.
              Without this, types are inferred differently:
              Consider (a+b)+1 and (a+b)."foo".
              In the first one, the "(" expression ends up with actualType int, in
              the second it ends up with actualType string. This is bad for cse,
              and type propagation (we rely on the fact that the same expression,
              with the same arguments, must have the same actual type).
            */
            m_exp->setExpectedType(TypePtr());
            rt = m_exp->getType();
            break;
        case '+':
        case '-':
            if (Type::SameType(expType, Type::Int64) ||
                    Type::SameType(expType, Type::Double)) {
                rt = expType;
            }
            break;
        case T_INC:
        case T_DEC:
            if (m_exp->is(Expression::KindOfSimpleVariable)) {
                FunctionScopePtr func =
                    dynamic_pointer_cast<FunctionScope>(ar->getScope());
                if (func) {
                    SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_exp);
                    VariableTablePtr variables = ar->getScope()->getVariables();
                    const std::string &name = var->getName();
                    if (variables->isParameter(name)) {
                        variables->addLvalParam(name);
                    }
                }
            }
        // fall through
        case '~':
            if (Type::SameType(expType, Type::Int64) ||
                    Type::SameType(expType, Type::Double) ||
                    Type::SameType(expType, Type::String)) {
                rt = expType;
            }
            break;
        default:
            break;
        }
    }

    return rt;
}
コード例 #23
0
void StaticStatement::inferTypes(AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  if (scope->inPseudoMain()) { // static just means to unset at global level
    for (int i = 0; i < m_exp->getCount(); i++) {
      ExpressionPtr exp = (*m_exp)[i];
      if (exp->is(Expression::KindOfAssignmentExpression)) {
        AssignmentExpressionPtr assignment_exp =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        ExpressionPtr variable = assignment_exp->getVariable();
        if (variable->is(Expression::KindOfSimpleVariable)) {
          SimpleVariablePtr var =
            dynamic_pointer_cast<SimpleVariable>(variable);
          var->setContext(Expression::Declaration);
          scope->getVariables()->forceVariant(ar, var->getName(),
                                              VariableTable::AnyStaticVars);
        } else {
          ASSERT(false);
        }
      } else {
        // Expression was optimized away; remove it
        m_exp->removeElement(i--);
      }
    }
    m_exp->inferTypes(ar, Type::Any, true);
    return;
  }
  scope->getVariables()->setAttribute(VariableTable::InsideStaticStatement);
  for (int i = 0; i < m_exp->getCount(); i++) {
    ExpressionPtr exp = (*m_exp)[i];
    VariableTablePtr variables = scope->getVariables();
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment_exp =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr variable = assignment_exp->getVariable();
      if (variable->is(Expression::KindOfSimpleVariable)) {
        SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable);
        var->setContext(Expression::Declaration);
        const std::string &name = var->getName();
        /* If we have already seen this variable in the current scope and
           it is not a static variable, record this variable as "redeclared"
           to force Variant type.
         */
        if (ar->isFirstPass()) {
          variables->checkRedeclared(name, KindOfStaticStatement);
        }
        /* If this is not a top-level static statement, the variable also
           needs to be Variant type. This should not be a common use case in
           php code.
         */
        if (!isTopLevel()) {
          variables->addNestedStatic(name);
        }

        if (variables->needLocalCopy(name)) {
          variables->forceVariant(ar, name, VariableTable::AnyStaticVars);
        }
      } else {
        ASSERT(false);
      }
    } else {
      // Expression was optimized away; remove it
      m_exp->removeElement(i--);
      continue;
    }
    exp->inferAndCheck(ar, Type::Any, false);
  }
  scope->getVariables()->clearAttribute(VariableTable::InsideStaticStatement);
}
コード例 #24
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(Variant::nullInit)",
                      Option::PropertyPrefix,
                      var->getName().c_str());
          } 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;
    }
  }
}
コード例 #25
0
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {

    if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return;

    bool wrapped = true;
    switch (m_op) {
    case T_CONCAT_EQUAL:
        if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) {
            SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1);
            ExpressionPtrVec ev;
            bool hasVoid = false;
            getConcatList(ev, m_exp2, hasVoid);
            cg_printf("%s", stringBufferName(Option::TempPrefix, prefix,
                                             sv->getName().c_str()).c_str());
            outputStringBufExprs(ev, cg, ar);
            return;
        }
        cg_printf("concat_assign");
        break;
    case '.':
    {
        ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
        ExpressionPtrVec ev;
        bool hasVoid = false;
        int num = getConcatList(ev, self, hasVoid);
        assert(!hasVoid);
        if (num <= MAX_CONCAT_ARGS) {
            assert(num >= 2);
            if (num == 2) {
                cg_printf("concat(");
            } else {
                if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num);
                cg_printf("concat%d(", num);
            }
            for (size_t i = 0; i < ev.size(); i++) {
                ExpressionPtr exp = ev[i];
                if (i) cg_printf(", ");
                outputStringExpr(cg, ar, exp, false);
            }
            cg_printf(")");
        } else {
            cg_printf("StringBuffer()");
            outputStringBufExprs(ev, cg, ar);
            cg_printf(".detach()");
        }
    }
    return;
    case T_LOGICAL_XOR:
        cg_printf("logical_xor");
        break;
    case '|':
        cg_printf("bitwise_or");
        break;
    case '&':
        cg_printf("bitwise_and");
        break;
    case '^':
        cg_printf("bitwise_xor");
        break;
    case T_IS_IDENTICAL:
        cg_printf("same");
        break;
    case T_IS_NOT_IDENTICAL:
        cg_printf("!same");
        break;
    case T_IS_EQUAL:
        cg_printf("equal");
        break;
    case T_IS_NOT_EQUAL:
        cg_printf("!equal");
        break;
    case '<':
        cg_printf("less");
        break;
    case T_IS_SMALLER_OR_EQUAL:
        cg_printf("not_more");
        break;
    case '>':
        cg_printf("more");
        break;
    case T_IS_GREATER_OR_EQUAL:
        cg_printf("not_less");
        break;
    case '/':
        cg_printf("divide");
        break;
    case '%':
        cg_printf("modulo");
        break;
    case T_INSTANCEOF:
        cg_printf("instanceOf");
        break;
    default:
        wrapped = !isUnused();
        break;
    }

    if (wrapped) cg_printf("(");

    ExpressionPtr first = m_exp1;
    ExpressionPtr second = m_exp2;

    // we could implement these functions natively on String and Array classes
    switch (m_op) {
    case '+':
    case '-':
    case '*':
    case '/':
        if (!first->outputCPPArithArg(cg, ar, m_op == '+')) {
            TypePtr argType = first->hasCPPTemp() ?
                              first->getType() : first->getActualType();
            bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
            first->outputCPP(cg, ar);
            if (flag) {
                cg_printf(")");
            }
        }
        break;
    case T_SL:
    case T_SR:
        ASSERT(first->getType()->is(Type::KindOfInt64));
        first->outputCPP(cg, ar);
        break;
    default:
        first->outputCPP(cg, ar);
        break;
    }

    switch (m_op) {
    case T_PLUS_EQUAL:
        cg_printf(" += ");
        break;
    case T_MINUS_EQUAL:
        cg_printf(" -= ");
        break;
    case T_MUL_EQUAL:
        cg_printf(" *= ");
        break;
    case T_DIV_EQUAL:
        cg_printf(" /= ");
        break;
    case T_MOD_EQUAL:
        cg_printf(" %%= ");
        break;
    case T_AND_EQUAL:
        cg_printf(" &= ");
        break;
    case T_OR_EQUAL:
        cg_printf(" |= ");
        break;
    case T_XOR_EQUAL:
        cg_printf(" ^= ");
        break;
    case T_SL_EQUAL:
        cg_printf(" <<= ");
        break;
    case T_SR_EQUAL:
        cg_printf(" >>= ");
        break;
    case T_BOOLEAN_OR:
        cg_printf(" || ");
        break;
    case T_BOOLEAN_AND:
        cg_printf(" && ");
        break;
    case T_LOGICAL_OR:
        cg_printf(" || ");
        break;
    case T_LOGICAL_AND:
        cg_printf(" && ");
        break;
    default:
        switch (m_op) {
        case '+':
            cg_printf(" + ");
            break;
        case '-':
            cg_printf(" - ");
            break;
        case '*':
            cg_printf(" * ");
            break;
        case T_SL:
            cg_printf(" << ");
            break;
        case T_SR:
            cg_printf(" >> ");
            break;
        default:
            cg_printf(", ");
            break;
        }
        break;
    }

    switch (m_op) {
    case '+':
    case '-':
    case '*':
    case '/':
        if (!second->outputCPPArithArg(cg, ar, m_op == '+')) {
            TypePtr argType = second->hasCPPTemp() ?
                              second->getType() : second->getActualType();
            bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
            second->outputCPP(cg, ar);
            if (flag) {
                cg_printf(")");
            }
        }
        break;
    case T_INSTANCEOF:
    {
        if (second->isScalar()) {
            ScalarExpressionPtr scalar =
                dynamic_pointer_cast<ScalarExpression>(second);
            bool notQuoted = scalar && !scalar->isQuoted();
            std::string s = second->getLiteralString();
            if (s == "static" && notQuoted) {
                cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
            } else if (s != "") {
                if (s == "self" && notQuoted) {
                    ClassScopeRawPtr cls = getOriginalClass();
                    if (cls) {
                        s = cls->getOriginalName();
                    }
                } else if (s == "parent" && notQuoted) {
                    ClassScopeRawPtr cls = getOriginalClass();
                    if (cls && !cls->getParent().empty()) {
                        s = cls->getParent();
                    }
                }
                cg_printString(s, ar, shared_from_this());
            } else {
                second->outputCPP(cg, ar);
            }
        } else {
            second->outputCPP(cg, ar);
        }
        break;
    }
    case T_PLUS_EQUAL:
    case T_MINUS_EQUAL:
    case T_MUL_EQUAL:
    {
        TypePtr t1 = first->getCPPType();
        TypePtr t2 = second->getType();
        if (t1 && !t1->is(Type::KindOfArray) &&
                t2 && Type::IsCastNeeded(ar, t2, t1)) {
            t1->outputCPPCast(cg, ar, getScope());
            cg_printf("(");
            second->outputCPP(cg, ar);
            cg_printf(")");
        } else {
            second->outputCPP(cg, ar);
        }
        break;
    }
    case T_BOOLEAN_OR:
    case T_BOOLEAN_AND:
    case T_LOGICAL_AND:
    case T_LOGICAL_OR:
        if (isUnused()) {
            cg_printf("(");
            if (second->outputCPPUnneeded(cg, ar)) {
                cg_printf(",");
            }
            cg_printf("false)");
        } else {
            second->outputCPP(cg, ar);
        }
        break;
    default:
        second->outputCPP(cg, ar);
    }

    if (wrapped) cg_printf(")");
}
コード例 #26
0
void ExpressionList::optimize(AnalysisResultConstPtr ar) {
  bool changed = false;
  size_t i = m_exps.size();
  if (m_kind != ListKindParam) {
    size_t skip = m_kind == ListKindLeft ? 0 : i - 1;
    while (i--) {
      if (i != skip) {
        ExpressionPtr &e = m_exps[i];
        if (!e || (e->getContainedEffects() == NoEffect && !e->isNoRemove())) {
          removeElement(i);
          changed = true;
        } else if (e->is(KindOfExpressionList)) {
          ExpressionListPtr el(static_pointer_cast<ExpressionList>(e));
          removeElement(i);
          for (size_t j = el->getCount(); j--; ) {
            insertElement((*el)[j], i);
          }
          changed = true;
        } else if (e->getLocalEffects() == NoEffect) {
          e = e->unneeded();
          // changed already handled by unneeded
        }
      }
    }
    if (m_exps.size() == 1) {
      // don't convert an exp-list with type assertions to
      // a ListKindWrapped
      if (!isNoRemove()) {
        m_kind = ListKindWrapped;
      }
    } else if (m_kind == ListKindLeft && m_exps[0]->isScalar()) {
      ExpressionPtr e = m_exps[0];
      removeElement(0);
      addElement(e);
      m_kind = ListKindWrapped;
    }
  } else {
    bool isUnset = hasContext(UnsetContext) &&
      // This used to be gated on ar->getPhase() >= PostOptimize
      false;
    int isGlobal = -1;
    while (i--) {
      ExpressionPtr &e = m_exps[i];
      if (isUnset) {
        if (e->is(Expression::KindOfSimpleVariable)) {
          SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(e);
          if (var->checkUnused()) {
            const std::string &name = var->getName();
            VariableTablePtr variables = getScope()->getVariables();
            if (!variables->isNeeded(name)) {
              removeElement(i);
              changed = true;
            }
          }
        }
      } else {
        bool global = e && (e->getContext() & Declaration) == Declaration;
        if (isGlobal < 0) {
          isGlobal = global;
        } else {
          always_assert(isGlobal == global);
        }
        if (isGlobal && e->isScalar()) {
          removeElement(i);
          changed = true;
        }
      }
    }
  }
  if (changed) {
    getScope()->addUpdates(BlockScope::UseKindCaller);
  }
}
コード例 #27
0
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {

  if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return;

  bool wrapped = true;
  switch (m_op) {
  case T_CONCAT_EQUAL:
    if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) {
      SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1);
      ExpressionPtrVec ev;
      bool hasVoid = false;
      getConcatList(ev, m_exp2, hasVoid);
      cg_printf("%s", stringBufferName(Option::TempPrefix, prefix,
                                       sv->getName().c_str()).c_str());
      outputStringBufExprs(ev, cg, ar);
      return;
    }
    cg_printf("concat_assign");
    break;
  case '.':
    {
      ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
      ExpressionPtrVec ev;
      bool hasVoid = false;
      int num = getConcatList(ev, self, hasVoid);
      assert(!hasVoid);
      if ((num <= MAX_CONCAT_ARGS ||
           (Option::GenConcat &&
            cg.getOutput() != CodeGenerator::SystemCPP))) {
        assert(num >= 2);
        if (num == 2) {
          cg_printf("concat(");
        } else {
          if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num);
          cg_printf("concat%d(", num);
        }
        for (size_t i = 0; i < ev.size(); i++) {
          ExpressionPtr exp = ev[i];
          if (i) cg_printf(", ");
          outputStringExpr(cg, ar, exp, false);
        }
        cg_printf(")");
      } else {
        cg_printf("StringBuffer()");
        outputStringBufExprs(ev, cg, ar);
        cg_printf(".detach()");
      }
    }
    return;
  case T_LOGICAL_XOR:         cg_printf("logical_xor");   break;
  case '|':                   cg_printf("bitwise_or");    break;
  case '&':                   cg_printf("bitwise_and");   break;
  case '^':                   cg_printf("bitwise_xor");   break;
  case T_IS_IDENTICAL:        cg_printf("same");          break;
  case T_IS_NOT_IDENTICAL:    cg_printf("!same");         break;
  case T_IS_EQUAL:            cg_printf("equal");         break;
  case T_IS_NOT_EQUAL:        cg_printf("!equal");        break;
  case '<':                   cg_printf("less");          break;
  case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more");      break;
  case '>':                   cg_printf("more");          break;
  case T_IS_GREATER_OR_EQUAL: cg_printf("not_less");      break;
  case '/':                   cg_printf("divide");        break;
  case '%':                   cg_printf("modulo");        break;
  case T_INSTANCEOF:          cg_printf("instanceOf");    break;
  default:
    wrapped = !isUnused();
    break;
  }

  if (wrapped) cg_printf("(");

  ExpressionPtr first = m_exp1;
  ExpressionPtr second = m_exp2;

  // we could implement these functions natively on String and Array classes
  switch (m_op) {
  case '+':
  case '-':
  case '*':
  case '/': {
    TypePtr actualType = first->getActualType();

    if (actualType &&
        (actualType->is(Type::KindOfString) ||
         (m_op != '+' && actualType->is(Type::KindOfArray)))) {
      cg_printf("(Variant)(");
      first->outputCPP(cg, ar);
      cg_printf(")");
    } else {
      bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope());
      first->outputCPP(cg, ar);
      if (flag) {
        cg_printf(")");
      }
    }
    break;
  }
  case T_SL:
  case T_SR:
    cg_printf("toInt64(");
    first->outputCPP(cg, ar);
    cg_printf(")");
    break;
  default:
    first->outputCPP(cg, ar);
    break;
  }

  switch (m_op) {
  case T_PLUS_EQUAL:          cg_printf(" += ");   break;
  case T_MINUS_EQUAL:         cg_printf(" -= ");   break;
  case T_MUL_EQUAL:           cg_printf(" *= ");   break;
  case T_DIV_EQUAL:           cg_printf(" /= ");   break;
  case T_MOD_EQUAL:           cg_printf(" %%= ");  break;
  case T_AND_EQUAL:           cg_printf(" &= ");   break;
  case T_OR_EQUAL:            cg_printf(" |= ");   break;
  case T_XOR_EQUAL:           cg_printf(" ^= ");   break;
  case T_SL_EQUAL:            cg_printf(" <<= ");  break;
  case T_SR_EQUAL:            cg_printf(" >>= ");  break;
  case T_BOOLEAN_OR:          cg_printf(" || ");   break;
  case T_BOOLEAN_AND:         cg_printf(" && ");   break;
  case T_LOGICAL_OR:          cg_printf(" || ");   break;
  case T_LOGICAL_AND:         cg_printf(" && ");   break;
  default:
    switch (m_op) {
    case '+':                   cg_printf(" + ");    break;
    case '-':                   cg_printf(" - ");    break;
    case '*':                   cg_printf(" * ");    break;
    case T_SL:                  cg_printf(" << ");   break;
    case T_SR:                  cg_printf(" >> ");   break;
    default:
      cg_printf(", ");
      break;
    }
    break;
  }

  switch (m_op) {
  case '+':
  case '-':
  case '*':
  case '/': {
    TypePtr actualType = second->getActualType();

    if (actualType &&
        (actualType->is(Type::KindOfString) ||
         (m_op != '+' && actualType->is(Type::KindOfArray)))) {
      cg_printf("(Variant)(");
      second->outputCPP(cg, ar);
      cg_printf(")");
    } else {
      bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope());
      second->outputCPP(cg, ar);
      if (flag) {
        cg_printf(")");
      }
    }
    break;
  }
  case T_INSTANCEOF:
    {
      if (second->isScalar()) {
        std::string s = second->getLiteralString();
        std::string sLower = Util::toLower(s);
        if (sLower != "") {
          cg_printString(sLower, ar, shared_from_this());
        } else {
          second->outputCPP(cg, ar);
        }
      } else {
        second->outputCPP(cg, ar);
      }
      break;
    }
  case T_PLUS_EQUAL:
  case T_MINUS_EQUAL:
  case T_MUL_EQUAL:
    {
      TypePtr t1 = first->getCPPType();
      TypePtr t2 = second->getType();
      if (t1 && !t1->is(Type::KindOfArray) &&
          t2 && Type::IsCastNeeded(ar, t2, t1)) {
        t1->outputCPPCast(cg, ar, getScope());
        cg_printf("(");
        second->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        second->outputCPP(cg, ar);
      }
      break;
    }
  case T_BOOLEAN_OR:
  case T_BOOLEAN_AND:
  case T_LOGICAL_AND:
  case T_LOGICAL_OR:
    if (isUnused()) {
      cg_printf("(");
      if (second->outputCPPUnneeded(cg, ar)) {
        cg_printf(",");
      }
      cg_printf("false)");
    } else {
      second->outputCPP(cg, ar);
    }
    break;
  default:
    second->outputCPP(cg, ar);
  }

  if (wrapped) cg_printf(")");
}
コード例 #28
0
void ClassVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->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;

    switch (cg.getContext()) {
    case CodeGenerator::CppConstructor:
      if (m_modifiers->isStatic()) continue;

      if (exp->is(Expression::KindOfAssignmentExpression)) {
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);

        var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        ExpressionPtr value = assignment->getValue();
        value->outputCPPBegin(cg, ar);
        if (derivFromRedec) {
          cg_printf("%sset(\"%s\",-1, ", Option::ObjectPrefix,
                    var->getName().c_str());
          value->outputCPP(cg, ar);
          cg_printf(")");
        } else {
          cg_printf("%s%s = ", Option::PropertyPrefix, var->getName().c_str());
          value->outputCPP(cg, ar);
        }
        cg_printf(";\n");
        value->outputCPPEnd(cg, ar);
      } else {
        var = dynamic_pointer_cast<SimpleVariable>(exp);
        if (derivFromRedec) {
          cg_printf("%sset(\"%s\",-1, null);\n", Option::ObjectPrefix,
                    var->getName().c_str());
        } else  {
          type = scope->getVariables()->getFinalType(var->getName());
          const char *initializer = type->getCPPInitializer();
          if (initializer) {
            cg_printf("%s%s = %s;\n", Option::PropertyPrefix,
                      var->getName().c_str(), initializer);
          }
        }
      }
      break;

    case CodeGenerator::CppStaticInitializer:
      {
        if (!m_modifiers->isStatic()) continue;

        VariableTablePtr variables = scope->getVariables();
        if (exp->is(Expression::KindOfAssignmentExpression)) {
          AssignmentExpressionPtr assignment =
            dynamic_pointer_cast<AssignmentExpression>(exp);

          var = dynamic_pointer_cast<SimpleVariable>
            (assignment->getVariable());
          ExpressionPtr value = assignment->getValue();
          if (value->containsDynamicConstant(ar)) continue;
          cg_printf("g->%s%s%s%s = ",
                    Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                    Option::IdPrefix.c_str(), var->getName().c_str());

          value->outputCPP(cg, ar);
        } else {
          var = dynamic_pointer_cast<SimpleVariable>(exp);
          type = scope->getVariables()->getFinalType(var->getName());
          const char *initializer = type->getCPPInitializer();
          if (initializer) {
            cg_printf("g->%s%s%s%s = %s",
                      Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                      Option::IdPrefix.c_str(), var->getName().c_str(),
                      initializer);
          }
        }
        cg_printf(";\n");
      }
      break;
    case CodeGenerator::CppLazyStaticInitializer:
      {
        if (!m_modifiers->isStatic()) continue;
        if (!exp->is(Expression::KindOfAssignmentExpression)) continue;
        VariableTablePtr variables = scope->getVariables();
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
        ExpressionPtr value = assignment->getValue();
        if (!value->containsDynamicConstant(ar)) continue;
        value->outputCPPBegin(cg, ar);
        cg_printf("g->%s%s%s%s = ",
                  Option::StaticPropertyPrefix, scope->getId(cg).c_str(),
                  Option::IdPrefix.c_str(), var->getName().c_str());
        value->outputCPP(cg, ar);
        cg_printf(";\n");
        value->outputCPPEnd(cg, ar);
      }
      break;
    default:
      break;
    }
  }
}
コード例 #29
0
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();


      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            ar->getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            ConstructPtr decl = vars->getDeclaration(m_globalName);
            if (decl) {
              ar->getDependencyGraph()->
                add(DependencyGraph::KindOfGlobalVariable,
                    ar->getName(),
                    m_globalName, self, m_globalName, decl);
            }
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            ar->getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }


      if (hasContext(LValue) || hasContext(RefValue)) {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseLDynamicVariable,
                                     self);
        }
        ar->getVariables()->forceVariants(ar);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      } else {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseRDynamicVariable,
                                     self);
        }
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, NEW_TYPE(Primitive), false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, NEW_TYPE(Sequence), false);
    m_offset->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::InvalidArrayElement,
                                   self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  if (hasContext(LValue) || hasContext(RefValue)) setEffect(CreateEffect);

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}
コード例 #30
0
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  if (m_offset &&
      !(m_context & (UnsetContext | ExistContext |
                     InvokeArgument | LValue | RefValue))) {
    setEffect(DiagnosticEffect);
  }
  if (m_context & (AssignmentLHS|OprLValue)) {
    clearEffect(AccessorEffect);
  } else if (m_context & (LValue | RefValue)) {
    setEffect(CreateEffect);
  }

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();

      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            clearEffect(DiagnosticEffect);
            getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }

      if (hasContext(LValue) || hasContext(RefValue)) {
        ar->getVariables()->forceVariants(ar, VariableTable::AnyVars);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, Type::Primitive, false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, coerce ? Type::AutoSequence :
                                        Type::Sequence, coerce);
    m_offset->inferAndCheck(ar, Type::Some, false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::InvalidArrayElement, self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}