TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  if (m_vars) {
    assert(m_values && m_values->getCount() == m_vars->getCount());

    // containing function's variable table (not closure function's)
    VariableTablePtr variables = getScope()->getVariables();

    // closure function's variable table
    VariableTablePtr cvariables = m_func->getFunctionScope()->getVariables();

    // force all reference use vars into variant for this function scope
    for (int i = 0; i < m_vars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
      const string &name = param->getName();
      if (param->isRef()) {
        variables->forceVariant(ar, name, VariableTable::AnyVars);
      }
    }

    // infer the types of the values
    m_values->inferAndCheck(ar, Type::Some, false);

    // coerce the types inferred from m_values into m_vars
    for (int i = 0; i < m_vars->getCount(); i++) {
      ExpressionPtr value = (*m_values)[i];
      ParameterExpressionPtr var =
        dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
      assert(!var->getExpectedType());
      assert(!var->getImplementedType());
      if (var->isRef()) {
        var->setActualType(Type::Variant);
      } else {
        TypePtr origVarType(var->getActualType() ?
                            var->getActualType() : Type::Some);
        var->setActualType(Type::Coerce(ar, origVarType, value->getType()));
      }
    }

    {
      // this lock isn't technically needed for thread-safety, since
      // the dependencies are all set up. however, the lock assertions
      // will fail if we don't acquire it.
      GET_LOCK(m_func->getFunctionScope());

      // bootstrap the closure function's variable table with
      // the types from m_vars
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();
        cvariables->addParamLike(name, param->getType(), ar,
                                 shared_from_this(),
                                 getScope()->isFirstPass());
      }
    }
  }
  return s_ClosureType;
}
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_func->analyzeProgram(ar);
  if (m_vars) {
    m_values->analyzeProgram(ar);

    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
      getFunctionScope()->addUse(m_func->getFunctionScope(),
                                 BlockScope::UseKindClosure);
      m_func->getFunctionScope()->setClosureVars(m_vars);

      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      VariableTablePtr containing = getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();
        {
          Symbol *containingSym = containing->addDeclaredSymbol(name, param);
          containingSym->setPassClosureVar();

          Symbol *sym = variables->addDeclaredSymbol(name, param);
          sym->setClosureVar();
          sym->setDeclaration(ConstructPtr());
          if (param->isRef()) {
            sym->setRefClosureVar();
            sym->setUsed();
          } else {
            sym->clearRefClosureVar();
            sym->clearUsed();
          }
        }
      }
      return;
    }
    if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        // so we can assign values to them, instead of seeing CVarRef
        Symbol *sym = variables->getSymbol(name);
        if (sym && sym->isParameter()) {
          sym->setLvalParam();
        }
      }
    }
  }

  FunctionScopeRawPtr container = 
    getFunctionScope()->getContainingNonClosureFunction();
  if (container && container->isStatic()) {
    m_func->getModifiers()->add(T_STATIC);
  }

}
void FunctionScope::outputCPPParamsCall(CodeGenerator &cg,
                                        AnalysisResultPtr ar,
                                        bool aggregateParams) {
  if (isVariableArgument()) {
    cg.printf("num_args, ");
  }
  bool userFunc = isUserFunction();
  ExpressionListPtr params;
  if (userFunc) {
    MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
    params = stmt->getParams();
  }
  if (aggregateParams) {
    cg.printf("Array(");
    if (m_maxParam) {
      // param arrays are always vectors
      cg.printf("ArrayInit(%d, true).", m_maxParam);
    }
  }
  for (int i = 0; i < m_maxParam; i++) {
    if (i > 0) cg.printf(aggregateParams ? "." : ", ");
    bool isRef;
    if (userFunc) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*params)[i]);
      isRef = param->isRef();
      if (aggregateParams) {
        cg.printf("set%s(%d, v_%s", isRef ? "Ref" : "", i,
                                    param->getName().c_str());
      } else {
        cg.printf("%sv_%s%s",
                  isRef ? "ref(" : "", param->getName().c_str(),
                  isRef ? ")" : "");
      }
    } else {
      isRef = isRefParam(i);
      if (aggregateParams) {
        cg.printf("set%s(%d, a%d", isRef ? "Ref" : "", i, i);
      } else {
        cg.printf("%sa%d%s",
                  isRef ? "ref(" : "", i, isRef ? ")" : "");
      }
    }
    if (aggregateParams) cg.printf(")");
  }
  if (aggregateParams) {
    if (m_maxParam) cg.printf(".create()");
    cg.printf(")");
  }
  if (isVariableArgument()) {
    if (aggregateParams || m_maxParam > 0) cg.printf(",");
    cg.printf("args");
  }
}
void FunctionScope::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
  for (int i = 0; i < m_callTempCountMax; i++) {
    cg_printf("Variant %s%d;\n", Option::EvalOrderTempPrefix, i);
  }

  ExpressionListPtr params =
    dynamic_pointer_cast<MethodStatement>(getStmt())->getParams();

  /* Typecheck parameters */
  for (size_t i = 0; i < m_paramTypes.size(); i++) {
    TypePtr specType = m_paramTypeSpecs[i];
    if (!specType)
      continue;
    if (specType->is(Type::KindOfSome) || specType->is(Type::KindOfAny)
      || specType->is(Type::KindOfVariant))
      continue;

    /* If there's any possible runtime conflict, this will be turned into
     * a Variant; if it hasn't been, then we don't need to worry */
    if (!getParamType(i)->is(Type::KindOfVariant))
      continue;

    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*params)[i]);

    /* Insert runtime checks. */
    if (specType->is(Type::KindOfArray)) {
      cg_printf("if(!%s%s.isArray())\n",
                Option::VariablePrefix, param->getName().c_str());
      cg_printf("  throw_unexpected_argument_type"
                "(%d,\"%s\",\"array\",%s%s);\n",
                i, m_name.c_str(),
                Option::VariablePrefix, param->getName().c_str());
    } else if (specType->is(Type::KindOfObject)) {
      cg_printf("if(!%s%s.instanceof(\"%s\"))\n", Option::VariablePrefix,
                param->getName().c_str(), specType->getName().c_str());
      cg_printf("  throw_unexpected_argument_type(%d,\"%s\",\"%s\",%s%s);\n",
                i, m_name.c_str(), specType->getName().c_str(),
                Option::VariablePrefix, param->getName().c_str());
    } else {
      Logger::Error("parameter %d of %s: improper type hint %s",
                    i, m_name.c_str(), specType->toString().c_str());
      return;
    }
  }

  BlockScope::outputCPP(cg, ar);
}
void MethodStatement::addParamRTTI(AnalysisResultPtr ar) {
  FunctionScopePtr func =
    dynamic_pointer_cast<FunctionScope>(ar->getScope());
  VariableTablePtr variables = func->getVariables();
  if (variables->getAttribute(VariableTable::ContainsDynamicVariable) ||
      variables->getAttribute(VariableTable::ContainsExtract)) {
    return;
  }
  for (int i = 0; i < m_params->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    const string &paramName = param->getName();
    if (variables->isLvalParam(paramName)) continue;
    TypePtr paramType = param->getActualType();
    if ((paramType->is(Type::KindOfVariant) ||
         paramType->is(Type::KindOfSome)) &&
        !param->isRef()) {
      param->setHasRTTI();
      ClassScopePtr cls = ar->getClassScope();
      ar->addParamRTTIEntry(cls, func, paramName);
      const string funcId = ar->getFuncId(cls, func);
      ar->addRTTIFunction(funcId);
    }
  }
}
void FunctionScope::setParamCounts(AnalysisResultPtr ar, int minParam,
                                   int maxParam) {
  m_minParam = minParam;
  m_maxParam = maxParam;
  ASSERT(m_minParam >= 0 && m_maxParam >= m_minParam);
  if (m_maxParam > 0) {
    m_paramNames.resize(m_maxParam);
    m_paramTypes.resize(m_maxParam);
    m_paramTypeSpecs.resize(m_maxParam);
    m_refs.resize(m_maxParam);

    if (m_stmt) {
      MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
      ExpressionListPtr params = stmt->getParams();

      for (int i = 0; i < m_maxParam; i++) {
        if (stmt->isRef(i)) m_refs[i] = true;

        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*params)[i]);
        m_paramNames[i] = param->getName();
        m_paramTypeSpecs[i] = param->getTypeSpec(ar);
      }
    }
  }
}
Exemple #7
0
void Symbol::beginLocal(BlockScopeRawPtr scope) {
  m_prevCoerced = m_coerced;
  if (isClosureVar()) {
    ExpressionListPtr useVars =
      scope->getContainingFunction()->getClosureVars();
    assert(useVars);
    // linear scan for now, since most use var lists are
    // fairly short
    bool found = false;
    for (int i = 0; i < useVars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*useVars)[i]);
      if (m_name == param->getName()) {
        // bootstrap use var with parameter type
        m_coerced = param->getType();
        found = true;
        break;
      }
    }
    if (!found) assert(false);
    assert(!isRefClosureVar() ||
           (m_coerced && m_coerced->is(Type::KindOfVariant)));
  } else {
    m_coerced.reset();
  }
}
void ClosureExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  cg_printf("%sClosure((NEWOBJ(%sClosure)())->create(\"%s\", ",
            Option::SmartPtrPrefix, Option::ClassPrefix,
            m_func->getOriginalName().c_str());

  if (m_vars && m_vars->getCount()) {
    cg_printf("Array(ArrayInit(%d, false, true)", m_vars->getCount());
    for (int i = 0; i < m_vars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
      ExpressionPtr value = (*m_values)[i];

      cg_printf(".set%s(\"%s\", ",
                param->isRef() ? "Ref" : "", param->getName().c_str());
      value->outputCPP(cg, ar);
      cg_printf(")");
    }
    cg_printf(".create())");
  } else {
    cg_printf("Array()");
  }

  cg_printf("))");
}
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
      m_func(func), m_vars(vars) {

  if (m_vars) {
    m_values = ExpressionListPtr
      (new ExpressionList(m_vars->getScope(), m_vars->getLocation(),
                          KindOfExpressionList));
    for (int i = 0; i < m_vars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
      string name = param->getName();

      SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                               param->getLocation(),
                                               KindOfSimpleVariable,
                                               name));
      if (param->isRef()) {
        var->setContext(RefValue);
      }
      m_values->addElement(var);
    }
  }
}
Exemple #10
0
void FunctionScope::setParamCounts(AnalysisResultConstPtr ar, int minParam,
                                   int numDeclParam) {
    if (minParam >= 0) {
        m_minParam = minParam;
        m_numDeclParams = numDeclParam;
    } else {
        assert(numDeclParam == minParam);
    }
    assert(m_minParam >= 0 && m_numDeclParams >= m_minParam);
    assert(IMPLIES(hasVariadicParam(), m_numDeclParams > 0));
    if (m_numDeclParams > 0) {
        m_paramNames.resize(m_numDeclParams);
        m_refs.resize(m_numDeclParams);

        if (m_stmt) {
            MethodStatementPtr stmt = dynamic_pointer_cast<MethodStatement>(m_stmt);
            ExpressionListPtr params = stmt->getParams();

            for (int i = 0; i < m_numDeclParams; i++) {
                if (stmt->isRef(i)) m_refs[i] = true;

                ParameterExpressionPtr param =
                    dynamic_pointer_cast<ParameterExpression>((*params)[i]);
                m_paramNames[i] = param->getName();
            }
            assert(m_paramNames.size() == m_numDeclParams);
        }
    }
}
Exemple #11
0
bool AliasManager::optimize(AnalysisResultPtr ar, MethodStatementPtr m) {
  m_arp = ar;

  m_variables = ar->getScope()->getVariables();
  if (!m_variables->isPseudoMainTable()) {
    m_variables->clearUsed();
  }

  if (ExpressionListPtr pPtr = m->getParams()) {
    ExpressionList &params = *pPtr;
    for (int i = params.getCount(); i--; ) {
      ParameterExpressionPtr p = spc(ParameterExpression, params[i]);
      AliasInfo &ai = m_aliasInfo[p->getName()];
      if (p->isRef()) {
        ai.setIsRefTo();
      }
    }
  }

  collectAliasInfoRecur(m->getStmts());

  for (AliasInfoMap::iterator it = m_aliasInfo.begin(),
         end = m_aliasInfo.end(); it != end; ++it) {
    if (m_variables->isGlobal(it->first) ||
        m_variables->isStatic(it->first)) {
      it->second.setIsGlobal();
    }
  }

  canonicalizeRecur(m->getStmts());
  return m_changed;
}
void MethodStatement::outputCPPArgInjections(CodeGenerator &cg,
                                             AnalysisResultPtr ar,
                                             const char *name,
                                             ClassScopePtr cls,
                                             FunctionScopePtr funcScope) {
  if (cg.getOutput() != CodeGenerator::SystemCPP) {
    if (m_params) {
      int n = m_params->getCount();
      cg_printf("INTERCEPT_INJECTION(\"%s\", ", name);
      if (Option::GenArrayCreate && !hasRefParam()) {
        ar->m_arrayIntegerKeySizes.insert(n);
        outputParamArrayCreate(cg, true);
        cg_printf(", %s);\n", funcScope->isRefReturn() ? "ref(r)" : "r");
      } else {
        cg_printf("(Array(ArrayInit(%d, true)", n);
        for (int i = 0; i < n; i++) {
          ParameterExpressionPtr param =
            dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
          const string &paramName = param->getName();
          cg_printf(".set%s(%d, %s%s)", param->isRef() ? "Ref" : "",
                    i, Option::VariablePrefix, paramName.c_str());
        }
        cg_printf(".create())), %s);\n",
                  funcScope->isRefReturn() ? "ref(r)" : "r");
      }
    } else {
      cg_printf("INTERCEPT_INJECTION(\"%s\", null_array, %s);\n",
                name, funcScope->isRefReturn() ? "ref(r)" : "r");
    }
  }

  if (Option::GenRTTIProfileData && m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->hasRTTI()) {
        const string &paramName = param->getName();
        int id = ar->getParamRTTIEntryId(cls, funcScope, paramName);
        if (id != -1) {
          cg_printf("RTTI_INJECTION(%s%s, %d);\n",
                    Option::VariablePrefix, paramName.c_str(), id);
        }
      }
    }
  }
}
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
  m_func->analyzeProgram(ar);

  if (m_vars) {
    m_values->analyzeProgram(ar);

    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
      m_func->getFunctionScope()->setClosureVars(m_vars);

      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();
        {
          Symbol *sym = variables->addSymbol(name);
          sym->setClosureVar();
          if (param->isRef()) {
            sym->setRefClosureVar();
          } else {
            sym->clearRefClosureVar();
          }
        }
      }
      return;
    }
    if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
      // closure function's variable table (not containing function's)
      VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();

        // so we can assign values to them, instead of seeing CVarRef
        Symbol *sym = variables->getSymbol(name);
        if (sym && sym->isParameter()) {
          sym->setLvalParam();
        }
      }
    }
  }
}
Exemple #14
0
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation()));
    // push the vars in reverse order, not retaining duplicates
    std::set<string> seenBefore;

    // Because PHP is insane you can have a use variable with the same
    // name as a param name.
    // In that case, params win (which is different than zend but much easier)
    ExpressionListPtr bodyParams = m_func->getParams();
    if (bodyParams) {
      int nParams = bodyParams->getCount();
      for (int i = 0; i < nParams; i++) {
        ParameterExpressionPtr par(
          static_pointer_cast<ParameterExpression>((*bodyParams)[i]));
        seenBefore.insert(par->getName());
      }
    }

    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      assert(param);
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
      assert(m_vars->getCount() == m_values->getCount());
    }
  }
}
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg,
                                                   AnalysisResultPtr ar,
                                                   const char *cls) {
  if (!m_modifiers->isStatic() || !m_stmt) return;

  CodeGenerator::Context context = cg.getContext();
  FunctionScopePtr funcScope = m_funcScope.lock();

  bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl ||
    context == CodeGenerator::CppTypedParamsWrapperImpl;

  bool needsWrapper = isWrapper ||
    (Option::HardTypeHints && funcScope->needsTypeCheckWrapper());

  m_modifiers->outputCPP(cg, ar);
  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg_printf("void");
  }
  cg_printf(" %s%s(", needsWrapper && !isWrapper ?
            Option::TypedMethodPrefix : Option::MethodPrefix,
            cg.formatLabel(m_name).c_str());
  if (!isWrapper) cg.setContext(CodeGenerator::CppStaticMethodWrapper);
  funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
  cg_printf(") { %s%s%s(", type ? "return " : "",
            needsWrapper && !isWrapper ?
            Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
            cg.formatLabel(m_name).c_str());
  cg_printf("%s%s::s_class_name", Option::ClassPrefix, cls);
  cg.setContext(context);
  if (funcScope->isVariableArgument()) {
    cg_printf(", num_args");
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      ASSERT(param);
      cg_printf(", %s%s", Option::VariablePrefix, param->getName().c_str());
    }
  }
  if (funcScope->isVariableArgument()) {
    cg_printf(", args");
  }
  cg_printf("); }\n");
  if (!isWrapper && needsWrapper) {
    cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
    outputCPPStaticMethodWrapper(cg, ar, cls);
    cg.setContext(context);
  }
}
void MethodStatement::outputCPPTypeCheckWrapper(CodeGenerator &cg,
                                                AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = getFunctionScope();
  TypePtr type = funcScope->getReturnType();
  bool isMethod = getClassScope();
  string fname = isMethod ? funcScope->getName() : funcScope->getId(cg);

  funcScope->outputCPP(cg, ar);
  cg_printf("%s%s%s(", type ? "return " : "",
            (isMethod ? (m_modifiers->isStatic() ?
                         Option::TypedMethodImplPrefix :
                         Option::TypedMethodPrefix) :
             Option::TypedFunctionPrefix),
            fname.c_str());
  if (getClassScope() && m_modifiers->isStatic()) {
    cg_printf("cls, ");
  }
  if (funcScope->isVariableArgument()) {
    cg_printf("num_args, ");
  }

  assert(m_params);

  for (int i = 0; i < m_params->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    ASSERT(param);
    if (i) cg_printf(", ");
    cg_printf("%s%s", Option::VariablePrefix,
              param->getName().c_str());
    if (TypePtr spec = funcScope->getParamTypeSpec(i)) {
      if (Type::SameType(spec, funcScope->getParamType(i))) {
        if (spec->is(Type::KindOfArray)) {
          cg_printf(".getArrayData()");
        } else {
          ClassScopePtr cls = ar->findClass(spec->getName());
          assert(cls && !cls->isRedeclaring());
          cg_printf(".getObjectData()");
        }
      }
    }
  }

  if (funcScope->isVariableArgument()) {
    cg_printf(", args");
  }
  cg_printf(");\n");
}
Exemple #17
0
void FunctionScope::getClosureUseVars(
    ParameterExpressionPtrIdxPairVec &useVars,
    bool filterUsed /* = true */) {
    useVars.clear();
    if (!m_closureVars) return;
    assert(isClosure());
    VariableTablePtr variables = getVariables();
    for (int i = 0; i < m_closureVars->getCount(); i++) {
        ParameterExpressionPtr param =
            dynamic_pointer_cast<ParameterExpression>((*m_closureVars)[i]);
        auto const& name = param->getName();
        if (!filterUsed || variables->isUsed(name)) {
            useVars.push_back(ParameterExpressionPtrIdxPair(param, i));
        }
    }
}
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation()));
    // push the vars in reverse order, not retaining duplicates
    std::set<string> seenBefore;
    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      assert(param);
      if (param->getName() == "this") {
        // "this" is automatically included.
        // Once we get rid of all the callsites, make this an error
        continue;
      }
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
      assert(m_vars->getCount() == m_values->getCount());
    }
  }
}
TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  m_func->inferTypes(ar);
  if (m_values) m_values->inferAndCheck(ar, Type::Some, false);
  if (m_vars) {
    // containing function's variable table (not closure function's)
    VariableTablePtr variables = getScope()->getVariables();
    for (int i = 0; i < m_vars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
      string name = param->getName();
      if (param->isRef()) {
        variables->forceVariant(ar, name, VariableTable::AnyVars);
      }
    }
  }
  return Type::CreateObjectType("Closure");
}
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation(),
                          KindOfExpressionList));
    // push the vars in reverse order, not retaining duplicates
    set<string> seenBefore;
    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      ASSERT(param);
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation(),
                            KindOfExpressionList));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 KindOfSimpleVariable,
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
    }
  }
}
Exemple #21
0
void ClosureExpression::initializeValuesFromVars() {
  if (!m_vars) return;

  m_values = ExpressionListPtr
    (new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
  for (int i = 0; i < m_vars->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
    const string &name = param->getName();

    SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                             param->getLocation(),
                                             name));
    if (param->isRef()) {
      var->setContext(RefValue);
    }
    m_values->addElement(var);
  }
  assert(m_vars->getCount() == m_values->getCount());
}
void MethodStatement::outputParamArrayCreate(CodeGenerator &cg, bool checkRef) {
  int n = m_params->getCount();
  ASSERT(n > 0);
  cg_printf("array_create%d(%d, ", n, n);
  for (int i = 0; i < n; i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    const string &paramName = param->getName();
    cg_printf("%d, ", i);
    if (checkRef && param->isRef()) {
      ASSERT(false);
      cg_printf("ref(%s%s)", Option::VariablePrefix, paramName.c_str());
    } else {
      cg_printf("%s%s", Option::VariablePrefix, paramName.c_str());
    }
    if (i < n - 1) {
      cg_printf(", ");
    } else {
      cg_printf(")");
    }
  }
}
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg,
                                                   AnalysisResultPtr ar,
                                                   const char *cls) {
  if (!m_modifiers->isStatic() || !m_stmt) return;
  FunctionScopePtr funcScope = m_funcScope.lock();
  ar->pushScope(funcScope);
  m_modifiers->outputCPP(cg, ar);
  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg.printf("void");
  }
  cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str());
  CodeGenerator::Context old = cg.getContext();
  cg.setContext(CodeGenerator::CppStaticMethodWrapper);
  funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
  cg.setContext(old);
  cg.printf(") { %s%s%s(\"%s\"", type ? "return " : "",
            Option::MethodImplPrefix, m_name.c_str(),
            cls);
  if (funcScope->isVariableArgument()) {
    cg.printf(", num_args");
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      ASSERT(param);
      cg.printf(", %s%s", Option::VariablePrefix, param->getName().c_str());
    }
  }
  if (funcScope->isVariableArgument()) {
    cg.printf(", args");
  }
  cg.printf("); }\n");
  ar->popScope();
}
Exemple #24
0
FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar,
                                                 FileScopePtr fs) {
  ConstructPtr self = shared_from_this();
  int minParam = 0, numDeclParam = 0;
  bool hasRef = false;
  bool hasVariadicParam = false;
  if (m_params) {
    std::set<string> names, allDeclNames;
    int i = 0;
    numDeclParam = m_params->getCount();
    ParameterExpressionPtr lastParam =
      dynamic_pointer_cast<ParameterExpression>(
        (*m_params)[numDeclParam - 1]);
    hasVariadicParam = lastParam->isVariadic();
    if (hasVariadicParam) {
      allDeclNames.insert(lastParam->getName());
      // prevent the next loop from visiting the variadic param and testing
      // its optionality. parsing ensures that the variadic capture param
      // can *only* be the last param.
      i = numDeclParam - 2;
    } else {
      i = numDeclParam - 1;
    }
    for (; i >= 0; --i) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      assert(!param->isVariadic());
      if (param->isRef()) { hasRef = true; }
      if (!param->isOptional()) {
        if (!minParam) minParam = i + 1;
      } else if (minParam && !param->hasTypeHint()) {
        Compiler::Error(Compiler::RequiredAfterOptionalParam, param);
      }
      allDeclNames.insert(param->getName());
    }

    // For the purpose of naming (having entered the the function body), a
    // variadic capture param acts as any other variable.
    for (i = (numDeclParam - 1); i >= 0; --i) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (names.find(param->getName()) != names.end()) {
        Compiler::Error(Compiler::RedundantParameter, param);
        for (int j = 0; j < 1000; j++) {
          string name = param->getName() + folly::to<string>(j);
          if (names.find(name) == names.end() &&
              allDeclNames.find(name) == allDeclNames.end()) {
            param->rename(name);
            break;
          }
        }
      }
      names.insert(param->getName());
    }
  }

  if (hasRef || m_ref) {
    m_attribute |= FileScope::ContainsReference;
  }
  if (hasVariadicParam) {
    m_attribute |= FileScope::VariadicArgumentParam;
  }

  vector<UserAttributePtr> attrs;
  if (m_attrList) {
    for (int i = 0; i < m_attrList->getCount(); ++i) {
      UserAttributePtr a =
        dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]);
      attrs.push_back(a);
    }
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  auto funcScope =
    std::make_shared<FunctionScope>(ar, m_method, m_originalName,
                                    stmt, m_ref, minParam, numDeclParam,
                                    m_modifiers, m_attribute, m_docComment,
                                    fs, attrs);
  if (!m_stmt) {
    funcScope->setVirtual();
  }
  setBlockScope(funcScope);

  funcScope->setParamCounts(ar, -1, -1);

  return funcScope;
}
FunctionScopePtr MethodStatement::onParseImpl(AnalysisResultPtr ar) {
  int minParam, maxParam;
  ConstructPtr self = shared_from_this();
  minParam = maxParam = 0;
  bool hasRef = false;
  if (m_params) {
    set<string> names;
    int i = 0;
    maxParam = m_params->getCount();
    for (; i < maxParam; i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->isRef()) hasRef = true;
      if (param->isOptional()) break;
      minParam++;
    }
    for (i++; i < maxParam; i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->isRef()) hasRef = true;
      if (!param->isOptional()) {
        ar->getCodeError()->record(self, CodeError::RequiredAfterOptionalParam,
                                   param);
        param->defaultToNull(ar);
      }
    }

    if (ar->isFirstPass()) {
      for (i = 0; i < maxParam; i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
        if (names.find(param->getName()) == names.end()) {
          names.insert(param->getName());
        } else {
          ar->getCodeError()->record(self,
                                     CodeError::RedundantParameter, param);
          for (int j = 0; j < 1000; j++) {
            string name = param->getName() + lexical_cast<string>(j);
            if (names.find(name) == names.end()) {
              param->rename(name);
              break;
            }
          }
        }
      }
    }
  }

  if (hasRef || m_ref) {
    m_attribute |= FileScope::ContainsReference;
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  FunctionScopePtr funcScope
    (new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam, maxParam,
                       m_modifiers, m_attribute, m_docComment,
                       ar->getFileScope()));
  if (!m_stmt) {
    funcScope->setVirtual();
  }
  m_funcScope = funcScope;

  // TODO: this may have to expand to a concept of "virtual" functions...
  if (ar->getClassScope()) {
    funcScope->disableInline();
    if (m_name.length() > 2 && m_name.substr(0,2) == "__") {
      bool magic = true;
      int paramCount = 0;
      if (m_name == "__destruct") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__call") {
        funcScope->setOverriding(Type::Variant, Type::String, Type::Array);
        paramCount = 2;
      } else if (m_name == "__set") {
        funcScope->setOverriding(Type::Variant, Type::String, Type::Variant);
        paramCount = 2;
      } else if (m_name == "__get") {
        funcScope->setOverriding(Type::Variant, Type::String);
        paramCount = 1;
      } else if (m_name == "__isset") {
        funcScope->setOverriding(Type::Boolean, Type::String);
        paramCount = 1;
      } else if (m_name == "__unset") {
        funcScope->setOverriding(Type::Variant, Type::String);
        paramCount = 1;
      } else if (m_name == "__sleep") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__wakeup") {
        funcScope->setOverriding(Type::Variant);
      } else if (m_name == "__set_state") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
        paramCount = 1;
      } else if (m_name == "__tostring") {
        funcScope->setOverriding(Type::String);
      } else if (m_name == "__clone") {
        funcScope->setOverriding(Type::Variant);
      } else {
        paramCount = -1;
        if (m_name != "__construct") {
          ar->getCodeError()->record(self, CodeError::UnknownMagicMethod,
                                     self);
          magic = false;
        }
      }
      if (paramCount >= 0 &&
          (paramCount != minParam || paramCount != maxParam)) {
        ar->getCodeError()->record(self, CodeError::InvalidMagicMethod,
                                   self);
        magic = false;
      }
      if (magic) funcScope->setMagicMethod();
    }
    // ArrayAccess methods
    else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") {
      if (m_name == "offsetexists") {
        funcScope->setOverriding(Type::Boolean, Type::Variant);
      } else if (m_name == "offsetget") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
      } else if (m_name == "offsetset") {
        funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant);
      } else if (m_name == "offsetunset") {
        funcScope->setOverriding(Type::Variant, Type::Variant);
      }
    }
  }

  return funcScope;
}
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr scope = getClassScope();

  if (outputFFI(cg, ar)) return;

  cg.setPHPLineNo(-1);

  CodeGenerator::Context context = cg.getContext();

  if (context == CodeGenerator::CppImplementation) {
    printSource(cg);
  }

  bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl ||
    context == CodeGenerator::CppTypedParamsWrapperImpl;

  bool needsWrapper = isWrapper ||
    (Option::HardTypeHints && funcScope->needsTypeCheckWrapper());

  const char *prefix = needsWrapper && !isWrapper ?
    Option::TypedMethodPrefix : Option::MethodPrefix;

  switch (context) {
    case CodeGenerator::CppDeclaration:
    case CodeGenerator::CppTypedParamsWrapperDecl:
    {
      if (!m_stmt && !funcScope->isPerfectVirtual()) {
        cg_printf("// ");
      }

      m_modifiers->outputCPP(cg, ar);

      if (!m_stmt || m_name == "__offsetget_lval" ||
          funcScope->isPerfectVirtual()) {
        cg_printf("virtual ");
      }
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg_printf("void");
      }
      if (m_name == "__offsetget_lval") {
        cg_printf(" &___offsetget_lval(");
      } else if (m_modifiers->isStatic() && m_stmt) {
        // Static method wrappers get generated as support methods
        cg_printf(" %s%s(CStrRef cls%s",
                  needsWrapper && !isWrapper ?
                  Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
                  cg.formatLabel(m_name).c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg_printf(" %s%s(", prefix, cg.formatLabel(m_name).c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      if (m_stmt) {
        cg_printf(");\n");
      } else if (funcScope->isPerfectVirtual()) {
        cg_printf(") { return throw_fatal(\"pure virtual\");}\n");
      } else {
        cg_printf(") = 0;\n");
      }

      if (context != CodeGenerator::CppTypedParamsWrapperDecl) {
        if (funcScope->isConstructor(scope)
            && !funcScope->isAbstract() && !scope->isInterface()) {
          funcScope->outputCPPCreateDecl(cg, ar);
        }
        if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
          outputCPPImpl(cg, ar);
          cg.setContext(context);
        }
      }
    }
    break;
    case CodeGenerator::CppImplementation:
    case CodeGenerator::CppTypedParamsWrapperImpl:
      if (m_stmt) {
        TypePtr type = funcScope->getReturnType();
        if (type) {
          type->outputCPPDecl(cg, ar);
        } else {
          cg_printf("void");
        }
        string origFuncName = getOriginalFullName();
        string funcSection = Option::FunctionSections[origFuncName];
        if (!funcSection.empty()) {
          cg_printf(" __attribute__ ((section (\".text.%s\")))",
                    funcSection.c_str());
        }

        if (m_name == "__offsetget_lval") {
          cg_printf(" &%s%s::___offsetget_lval(",
                    Option::ClassPrefix, scope->getId(cg).c_str());
        } else if (m_modifiers->isStatic()) {
          cg_printf(" %s%s::%s%s(CStrRef cls%s", Option::ClassPrefix,
                    scope->getId(cg).c_str(),
                    needsWrapper && !isWrapper ?
                    Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
                    cg.formatLabel(m_name).c_str(),
                    funcScope->isVariableArgument() ||
                    (m_params && m_params->getCount()) ? ", " : "");
        } else {
          cg_printf(" %s%s::%s%s(", Option::ClassPrefix,
                    scope->getId(cg).c_str(),
                    prefix, cg.formatLabel(m_name).c_str());
        }
        funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
        cg_indentBegin(") {\n");
        if (context != CodeGenerator::CppTypedParamsWrapperImpl) {
          if (m_stmt->hasBody()) {
            const char *sys =
              (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : "");
            if (m_modifiers->isStatic()) {
              cg_printf("STATIC_METHOD_INJECTION%s(%s, %s);\n", sys,
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            } else if (cg.getOutput() != CodeGenerator::SystemCPP &&
                       !scope->isRedeclaring() && !scope->derivedByDynamic()) {
              cg_printf("INSTANCE_METHOD_INJECTION_ROOTLESS(%s, %s);\n",
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            } else {
              cg_printf("INSTANCE_METHOD_INJECTION%s(%s, %s);\n", sys,
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            }
          }
          outputCPPArgInjections(cg, ar, origFuncName.c_str(),
                                 scope, funcScope);
          if (m_name == "__offsetget_lval") {
            ParameterExpressionPtr param =
              dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
            cg_printf("Variant &v = %s->__lvalProxy;\n", cg.getGlobals(ar));
            string lowered = Util::toLower(m_originalName);
            cg_printf("v = %s%s(%s%s);\n",
                      prefix, lowered.c_str(),
                      Option::VariablePrefix, param->getName().c_str());
            cg_printf("return v;\n");
          } else {
            if (funcScope->isConstructor(scope)) {
              cg_printf("bool oldInCtor = gasInCtor(true);\n");
            } else if (m_name == "__destruct") {
              cg_printf("setInDtor();\n");
            }
            funcScope->outputCPP(cg, ar);
            cg.setContext(
              CodeGenerator::NoContext); // no inner functions/classes
            if (!funcScope->isStatic() && funcScope->getVariables()->
                getAttribute(VariableTable::ContainsDynamicVariable)) {
              cg_printf("%sthis = this;\n", Option::VariablePrefix);
            }
            outputCPPStmt(cg, ar);
          }
          cg_indentEnd("}\n");
          if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) {
            cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl);
            outputCPPImpl(cg, ar);
          }
        } else {
          outputCPPTypeCheckWrapper(cg, ar);
          cg_indentEnd("}\n");
        }
        cg.setContext(context);
        cg.printImplSplitter();
      }
      break;
    default:
      break;
  }
}
void MethodStatement::inferFunctionTypes(AnalysisResultPtr ar) {
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getFunctionScope());

  FunctionScopeRawPtr funcScope = getFunctionScope();
  bool pseudoMain = funcScope->inPseudoMain();

  if (m_stmt && funcScope->isFirstPass()) {
    if (pseudoMain ||
        funcScope->getReturnType() ||
        m_stmt->hasRetExp()) {
      bool lastIsReturn = false;
      if (m_stmt->getCount()) {
        StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1];
        if (lastStmt->is(Statement::KindOfReturnStatement)) {
          lastIsReturn = true;
        }
      }
      if (!lastIsReturn) {
        ExpressionPtr constant =
          makeScalarExpression(ar, funcScope->inPseudoMain() ?
                               Variant(1) :
                               Variant(Variant::NullInit()));
        ReturnStatementPtr returnStmt =
          ReturnStatementPtr(
            new ReturnStatement(getScope(), getLocation(), constant));
        m_stmt->addElement(returnStmt);
      }
    }
  }

  if (m_params) {
    m_params->inferAndCheck(ar, Type::Any, false);
  }

  // must also include params and use vars if this is a generator. note: we are
  // OK reading the params from the AST nodes of the original generator
  // function, since we have the dependency links set up
  if (funcScope->isGenerator()) {
    // orig function params
    MethodStatementRawPtr m = getOrigGeneratorFunc();
    assert(m);

    VariableTablePtr variables = funcScope->getVariables();
    ExpressionListPtr params = m->getParams();
    if (params) {
      for (int i = 0; i < params->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*params)[i]);
        const string &name = param->getName();
        assert(!param->isRef() || param->getType()->is(Type::KindOfVariant));
        variables->addParamLike(name, param->getType(), ar, param,
                                funcScope->isFirstPass());
      }
    }

    // use vars
    ExpressionListPtr useVars = m->getFunctionScope()->getClosureVars();
    if (useVars) {
      for (int i = 0; i < useVars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*useVars)[i]);
        const string &name = param->getName();
        assert(!param->isRef() || param->getType()->is(Type::KindOfVariant));
        variables->addParamLike(name, param->getType(), ar, param,
                                funcScope->isFirstPass());
      }
    }
  }

  if (m_stmt) {
    m_stmt->inferTypes(ar);
  }
}
FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar,
                                                 FileScopePtr fs) {
  int minParam, maxParam;
  ConstructPtr self = shared_from_this();
  minParam = maxParam = 0;
  bool hasRef = false;
  if (m_params) {
    std::set<string> names, allDeclNames;
    int i = 0;
    maxParam = m_params->getCount();
    for (i = maxParam; i--; ) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (param->isRef()) hasRef = true;
      if (!param->isOptional()) {
        if (!minParam) minParam = i + 1;
      } else if (minParam && !param->hasTypeHint()) {
        Compiler::Error(Compiler::RequiredAfterOptionalParam, param);
      }
      allDeclNames.insert(param->getName());
    }

    for (i = maxParam-1; i >= 0; i--) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      if (names.find(param->getName()) != names.end()) {
        Compiler::Error(Compiler::RedundantParameter, param);
        for (int j = 0; j < 1000; j++) {
          string name = param->getName() + lexical_cast<string>(j);
          if (names.find(name) == names.end() &&
              allDeclNames.find(name) == allDeclNames.end()) {
            param->rename(name);
            break;
          }
        }
      }
      names.insert(param->getName());
    }
  }

  if (hasRef || m_ref) {
    m_attribute |= FileScope::ContainsReference;
  }

  vector<UserAttributePtr> attrs;
  if (m_attrList) {
    for (int i = 0; i < m_attrList->getCount(); ++i) {
      UserAttributePtr a =
        dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]);
      attrs.push_back(a);
    }
  }

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  FunctionScopePtr funcScope
    (new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam, maxParam,
                       m_modifiers, m_attribute, m_docComment, fs, attrs));
  if (!m_stmt) {
    funcScope->setVirtual();
  }
  setBlockScope(funcScope);

  funcScope->setParamCounts(ar, -1, -1);
  return funcScope;
}
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);
}
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr scope = ar->getClassScope();
  string origFuncName;
  ar->pushScope(funcScope);

  if (outputFFI(cg, ar)) return;

  cg.setPHPLineNo(-1);

  if (cg.getContext() == CodeGenerator::CppImplementation) {
    printSource(cg);
  }

  switch (cg.getContext()) {
  case CodeGenerator::CppDeclaration:
    {
      if (!m_stmt) {
        cg.printf("// ");
      }
      m_modifiers->outputCPP(cg, ar);

      if (m_name == "__offsetget_lval") {
        cg.printf("virtual ");
      }
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg.printf("void");
      }
      if (m_name == "__lval") {
        cg.printf(" &___lval(");
      } else if (m_name == "__offsetget_lval") {
        cg.printf(" &___offsetget_lval(");
      } else if (m_modifiers->isStatic() && m_stmt) {
        // Static method wrappers get generated as support methods
        cg.printf(" %s%s(const char* cls%s", Option::MethodImplPrefix,
                  m_name.c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      if (m_stmt) {
        cg.printf(");\n");
      } else {
        cg.printf(") = 0;\n");
      }

      if (funcScope->isConstructor(scope)
       && !funcScope->isAbstract() && !scope->isInterface()) {
        funcScope->outputCPPCreateDecl(cg, ar);
      }
    }
    break;
  case CodeGenerator::CppImplementation:
    if (m_stmt) {
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg.printf("void");
      }
      origFuncName = std::string(scope->getOriginalName()) +
                     "::" + m_originalName;
      if (Option::HotFunctions.find(origFuncName) !=
          Option::HotFunctions.end()) {
        cg.printf(" __attribute((__section__(\".text.hot\")))");
      } else if (Option::ColdFunctions.find(origFuncName) !=
                 Option::ColdFunctions.end()) {
        cg.printf(" __attribute((__section__(\".text.cold\")))");
      }
      if (m_name == "__lval") {
        cg.printf(" &%s%s::___lval(",
                  Option::ClassPrefix, scope->getId().c_str());
      } else if (m_name == "__offsetget_lval") {
        cg.printf(" &%s%s::___offsetget_lval(",
                  Option::ClassPrefix, scope->getId().c_str());
      } else if (m_modifiers->isStatic()) {
        cg.printf(" %s%s::%s%s(const char* cls%s", Option::ClassPrefix,
                  scope->getId().c_str(),
                  Option::MethodImplPrefix, m_name.c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg.printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId().c_str(),
                  Option::MethodPrefix, m_name.c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg.indentBegin(") {\n");
      if (m_modifiers->isStatic()) {
        cg.printf("STATIC_METHOD_INJECTION(%s, %s::%s);\n",
                  scope->getOriginalName(), scope->getOriginalName(),
                  m_originalName.c_str());
      } else {
        cg.printf("INSTANCE_METHOD_INJECTION(%s, %s::%s);\n",
                  scope->getOriginalName(), scope->getOriginalName(),
                  m_originalName.c_str());
      }
      if (Option::GenRTTIProfileData && m_params) {
        for (int i = 0; i < m_params->getCount(); i++) {
          ParameterExpressionPtr param =
            dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
          if (param->hasRTTI()) {
            const string &paramName = param->getName();
            int id = ar->getParamRTTIEntryId(ar->getClassScope(), funcScope,
                                             paramName);
            if (id != -1) {
              cg.printf("RTTI_INJECTION(%s%s, %d);\n",
                        Option::VariablePrefix, paramName.c_str(), id);
            }
          }
        }
      }
      if (m_name == "__lval" || m_name == "__offsetget_lval") {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
        cg.printf("Variant &v = %s->__lvalProxy;\n",
                  cg.getOutput() == CodeGenerator::SystemCPP ?
                  "get_system_globals()" : "get_global_variables()");
        string lowered = Util::toLower(m_originalName);
        cg.printf("v = %s%s(%s%s);\n",
                  Option::MethodPrefix, lowered.c_str(),
                  Option::VariablePrefix, param->getName().c_str());
        cg.printf("return v;\n");
      } else {
        if (funcScope->isConstructor(scope)) {
          cg.printf("bool oldInCtor = gasInCtor(true);\n");
        } else if (m_name == "__destruct") {
          cg.printf("setInDtor();\n");
        } else if (m_name == "__call") {
          ParameterExpressionPtr param;
          if (m_params->getCount() > 0) {
            param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
            cg.printf("INCALL_HELPER(%s%s);\n",
                      Option::VariablePrefix, param->getName().c_str());
          } else {
            cg.printf("INCALL_HELPER(\"\");\n");
          }
        }
        funcScope->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        if (!funcScope->isStatic() && funcScope->getVariables()->
            getAttribute(VariableTable::ContainsDynamicVariable)) {
          cg.printf("%sthis = this;\n", Option::VariablePrefix);
        }
        outputCPPStmt(cg, ar);
        cg.setContext(CodeGenerator::CppImplementation);
      }
      cg.indentEnd("} /* function */\n");
    }
    break;
  default:
    break;
  }

  ar->popScope();
}