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 ¶mName = 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); } } } }
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); } } }
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); } } }
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 ¶ms = *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 ¶mName = 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 ¶mName = 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(); } } } } }
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"); }
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); } } } }
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 ¶mName = 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(); }
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 ¶mName = 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(); }