void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar->isAnalyzeInclude()) { if (funcScope->isSepExtension() || BuiltinSymbols::IsDeclaredDynamic(m_name) || Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) { funcScope->setDynamic(); } } funcScope->setIncludeLevel(ar->getIncludeLevel()); if (m_params) { m_params->analyzeProgram(ar); if (Option::GenRTTIProfileData && ar->getPhase() == AnalysisResult::AnalyzeFinal) { addParamRTTI(ar); } } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->isAnalyzeInclude()) { if (!funcScope->isStatic() && getClassScope() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { // Add this to variable table if we'll need it in a lookup table // Use object because there's no point to specializing, just makes // code gen harder when dealing with redeclared classes. TypePtr tp(Type::Object); funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(), ModifierExpressionPtr()); } FunctionScope::RecordRefParamInfo(m_name, funcScope); } }
void ParameterExpression::analyzeProgram(AnalysisResultPtr ar) { if (!m_type.empty()) addUserClass(ar, m_type); if (m_defaultValue) m_defaultValue->analyzeProgram(ar); if (ar->isAnalyzeInclude()) { // Have to use non const ref params for magic methods FunctionScopePtr fs = getFunctionScope(); fs->getVariables()->addParam(m_name, TypePtr(), ar, ExpressionPtr()); if (fs->isMagicMethod() || fs->getName() == "offsetget") { fs->getVariables()->addLvalParam(m_name); } } }
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 SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { Expression::analyzeProgram(ar); if (m_name == "argc" || m_name == "argv") { // special case: they are NOT superglobals when not in global scope if (ar->getScope() == ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); } } else { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); } if (m_superGlobal) { ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } if (m_name == "this" && ar->getClassScope()) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); func->setContainsThis(); m_this = true; } else if (m_name == "GLOBALS") { m_globals = true; } if (!(m_context & AssignmentLHS)) { BlockScopePtr scope = ar->getScope(); FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func) { func->getVariables()->addUsed(m_name); } } }
void FunctionScope::RecordFunctionInfo(std::string fname, FunctionScopePtr func) { VariableTablePtr variables = func->getVariables(); if (Option::WholeProgram) { Lock lock(s_refParamInfoLock); FunctionInfoPtr &info = s_refParamInfo[fname]; if (!info) { info = std::make_shared<FunctionInfo>(); } if (func->isStatic()) { info->setMaybeStatic(); } if (func->isRefReturn()) { info->setMaybeRefReturn(); } if (func->isReferenceVariableArgument()) { info->setRefVarArg(func->getMaxParamCount()); } for (int i = 0; i < func->getMaxParamCount(); i++) { if (func->isRefParam(i)) info->setRefParam(i); } } auto limit = func->getDeclParamCount(); for (int i = 0; i < limit; i++) { variables->addParam(func->getParamName(i), AnalysisResultPtr(), ConstructPtr()); } }
void FunctionCall::markRefParams(FunctionScopePtr func, const std::string &fooBarName) { ExpressionList ¶ms = *m_params; if (func) { int mpc = func->getMaxParamCount(); for (int i = params.getCount(); i--; ) { ExpressionPtr p = params[i]; if (i < mpc ? func->isRefParam(i) : func->isReferenceVariableArgument()) { p->setContext(Expression::RefValue); } else if (i < mpc && p->hasContext(RefParameter)) { Symbol *sym = func->getVariables()->addSymbol(func->getParamName(i)); sym->setLvalParam(); sym->setCallTimeRef(); } } } else if (Option::WholeProgram && !m_origName.empty()) { FunctionScope::FunctionInfoPtr info = FunctionScope::GetFunctionInfo(m_origName); if (info) { for (int i = params.getCount(); i--; ) { if (info->isRefParam(i)) { m_params->markParam(i); } } } // If we cannot find information of the so-named function, it might not // exist, or it might go through __call(), either of which cannot have // reference parameters. } else { for (int i = params.getCount(); i--; ) { m_params->markParam(i); } } }
void FunctionStatement::analyzeProgramImpl(AnalysisResultPtr ar) { FunctionScopePtr func = getScope()->getOuterScope()->getContainingFunction(); FunctionScopeRawPtr fs = getFunctionScope(); // redeclared functions are automatically volatile if (func && fs->isVolatile()) { func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer); } MethodStatement::analyzeProgramImpl(ar); }
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); // registering myself as a parent in dependency graph, so that // (1) we can tell orphaned parents // (2) overwrite non-master copy of function declarations if (ar->isFirstPass()) { ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall, "", getFullName(), shared_from_this()); if (Option::AllDynamic || hasHphpNote("Dynamic") || funcScope->isSepExtension() || BuiltinSymbols::IsDeclaredDynamic(m_name) || Option::IsDynamicFunction(m_method, m_name)) { funcScope->setDynamic(); } if (hasHphpNote("Volatile")) funcScope->setVolatile(); } funcScope->setIncludeLevel(ar->getIncludeLevel()); ar->pushScope(funcScope); if (m_params) { m_params->analyzeProgram(ar); if (Option::GenRTTIProfileData && ar->getPhase() == AnalysisResult::AnalyzeFinal) { addParamRTTI(ar); } } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->isFirstPass()) { if (!funcScope->isStatic() && ar->getClassScope() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { // Add this to variable table if we'll need it in a lookup table // Use object because there's no point to specializing, just makes // code gen harder when dealing with redeclared classes. TypePtr tp(NEW_TYPE(Object)); funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(), ModifierExpressionPtr()); } FunctionScope::RecordRefParamInfo(m_name, funcScope); } ar->popScope(); }
void walk_function(const FunctionScopePtr& fscope) { if (fscope->isClosure()) return; auto ms = dynamic_pointer_cast<MethodStatement>(fscope->getStmt()); ConstructPtr node(ms->getStmts()); with_scope( fscope->getVariables(), [&] { walk_ast(node); } ); }
void ParameterExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); VariableTablePtr variables = func->getVariables(); TypePtr paramType = func->getParamType(cg.getItemIndex()); bool isCVarRef = false; if (cg.getContext() == CodeGenerator::CppStaticMethodWrapper || (!variables->isLvalParam(m_name) && !variables->getAttribute(VariableTable::ContainsDynamicVariable) && !variables->getAttribute(VariableTable::ContainsExtract) && !m_ref)) { if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("CVarRef"); isCVarRef = true; } else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef"); else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef"); else paramType->outputCPPDecl(cg, ar); } else { paramType->outputCPPDecl(cg, ar); } cg_printf(" %s%s", Option::VariablePrefix, m_name.c_str()); if (m_defaultValue) { CodeGenerator::Context context = cg.getContext(); bool comment = context == CodeGenerator::CppImplementation || (context == CodeGenerator::CppDeclaration && func->isInlined()); if (comment) { cg_printf(" // "); } cg_printf(" = "); ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_defaultValue); if (isCVarRef && con && con->isNull()) { cg_printf("null_variant"); } else { if (comment) { cg.setContext(CodeGenerator::CppParameterDefaultValueImpl); } else { cg.setContext(CodeGenerator::CppParameterDefaultValueDecl); } m_defaultValue->outputCPP(cg, ar); cg.setContext(context); } if (comment) { cg_printf("\n"); } } }
void ParameterExpression::parseHandler(AnalysisResultConstPtr ar, FunctionScopePtr func, ClassScopePtr cls) { if (cls && !m_type.empty()) { if (m_type == "self") { m_type = cls->getName(); } else if (m_type == "parent") { if (!cls->getParent().empty()) { m_type = cls->getParent(); } } } func->getVariables()->addParam(m_name, TypePtr(), ar, ExpressionPtr()); }
void ParameterExpression::analyzeProgram(AnalysisResultPtr ar) { if (m_defaultValue) m_defaultValue->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (!m_type.empty()) { addUserClass(ar, m_type); } // Have to use non const ref params for magic methods FunctionScopePtr fs = getFunctionScope(); if (fs->isMagicMethod() || fs->getName() == "offsetget") { fs->getVariables()->addLvalParam(m_name); } if (m_ref) fs->setNeedsCheckMem(); } }
void FunctionScope::RecordRefParamInfo(string fname, FunctionScopePtr func) { RefParamInfoPtr info = s_refParamInfo[fname]; if (!info) { info = RefParamInfoPtr(new RefParamInfo()); s_refParamInfo[fname] = info; } if (func->isReferenceVariableArgument()) { info->setRefVarArg(func->getMaxParamCount()); } VariableTablePtr variables = func->getVariables(); for (int i = 0; i < func->getMaxParamCount(); i++) { if (func->isRefParam(i)) info->setRefParam(i); variables->addParam(func->getParamName(i), TypePtr(), AnalysisResultPtr(), ConstructPtr()); } }
void FunctionStatement::analyzeProgramImpl(AnalysisResultPtr ar) { // registering myself as a parent in dependency graph, so that // (1) we can tell orphaned parents // (2) overwrite non-master copy of function declarations if (ar->isFirstPass()) { if (m_loc) { ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall, "", m_name, shared_from_this()); } // else it's pseudoMain or artificial functions we added } FunctionScopePtr func = ar->getFunctionScope(); // containing function scope FunctionScopePtr fs = m_funcScope.lock(); // redeclared functions are automatically volatile if (func && fs->isVolatile()) { func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer); } MethodStatement::analyzeProgramImpl(ar); }
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } ClassScopePtr classScope = m_classScope.lock(); if (hasHphpNote("Volatile")) classScope->setVolatile(); FunctionScopePtr func = ar->getFunctionScope(); // redeclared classes are automatically volatile if (classScope->isVolatile()) { func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer); } if (m_stmt) { ar->pushScope(classScope); m_stmt->analyzeProgram(ar); ar->popScope(); } DependencyGraphPtr dependencies = ar->getDependencyGraph(); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation, m_originalName, cls->getOriginalName())) { ClassScopePtr classScope = m_classScope.lock(); ar->getCodeError()->record(CodeError::InvalidDerivation, shared_from_this(), ConstructPtr(), cls->getOriginalName()); m_parent = ""; m_base = ExpressionListPtr(); classScope->clearBases(); } else if (cls->isUserClass()) { dependencies->add(DependencyGraph::KindOfClassDerivation, ar->getName(), m_originalName, shared_from_this(), cls->getOriginalName(), cls->getStmt()); } } } }
void DynamicFunctionCall::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); if (ar->getPhase() >= AnalysisResult::AnalyzeAll) { if (!m_className.empty()) { resolveClass(); } if (!m_class) { addUserClass(ar, m_className); } if (m_params) { m_params->markParams(canInvokeFewArgs()); } if (!m_class && m_className.empty()) { FunctionScopePtr fs = getFunctionScope(); VariableTablePtr vt = fs->getVariables(); vt->setAttribute(VariableTable::ContainsDynamicFunctionCall); } } }
bool ObjectPropertyExpression::directVariantProxy(AnalysisResultPtr ar) { TypePtr actualType = m_object->getActualType(); if (actualType && actualType->is(Type::KindOfVariant)) { if (m_object->is(KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_object); const std::string &name = var->getName(); FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); VariableTablePtr variables = func->getVariables(); if (!variables->isParameter(name) || variables->isLvalParam(name)) { return true; } if (variables->getAttribute(VariableTable::ContainsDynamicVariable) || variables->getAttribute(VariableTable::ContainsExtract)) { return true; } } else { return true; } } return false; }
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; } }
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 ParameterExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); VariableTablePtr variables = func->getVariables(); Symbol *sym = variables->getSymbol(m_name); assert(sym && sym->isParameter()); bool inHeader = cg.isFileOrClassHeader(); cg.setFileOrClassHeader(true); CodeGenerator::Context context = cg.getContext(); bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppTypedParamsWrapperDecl); TypePtr paramType = typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ? Type::Variant : func->getParamType(sym->getParameterIndex()); bool wrapper = typedWrapper || context == CodeGenerator::CppFunctionWrapperImpl || context == CodeGenerator::CppFunctionWrapperDecl; bool isCVarRef = false; const char *prefix = ""; if (m_ref) { cg_printf("VRefParam"); if (!wrapper) { prefix = "r"; } } else if (wrapper || (!variables->isLvalParam(m_name) && !variables->getAttribute(VariableTable::ContainsDynamicVariable) && !variables->getAttribute(VariableTable::ContainsExtract))) { if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("CVarRef"); isCVarRef = true; } else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef"); else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef"); else paramType->outputCPPDecl(cg, ar, getScope()); } else { paramType->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s%s", prefix, Option::VariablePrefix, CodeGenerator::FormatLabel(m_name).c_str()); if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) { bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl || context == CodeGenerator::CppFunctionWrapperImpl || context == CodeGenerator::CppImplementation || (context == CodeGenerator::CppDeclaration && func->isInlined()); if (comment) { cg_printf(" // "); } cg_printf(" = "); ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_defaultValue); bool done = false; if (con && con->isNull()) { done = true; if (isCVarRef) { cg_printf("null_variant"); } else if (paramType->is(Type::KindOfVariant) || paramType->is(Type::KindOfSome)) { cg_printf("null"); } else if (paramType->is(Type::KindOfObject)) { cg_printf("Object()"); } else if (paramType->is(Type::KindOfArray)) { cg_printf("Array()"); } else if (paramType->is(Type::KindOfString)) { cg_printf("String()"); } else { done = false; } } if (!done) { if (comment) { cg.setContext(CodeGenerator::CppParameterDefaultValueImpl); } else { cg.setContext(CodeGenerator::CppParameterDefaultValueDecl); } bool isScalar = m_defaultValue->isScalar(); if (isCVarRef && isScalar) { ASSERT(!cg.hasScalarVariant()); cg.setScalarVariant(); } m_defaultValue->outputCPP(cg, ar); if (isCVarRef && isScalar) cg.clearScalarVariant(); ASSERT(!cg.hasScalarVariant()); cg.setContext(context); } if (comment) { cg_printf("\n"); } } cg.setFileOrClassHeader(inHeader); }
void FunctionStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { CodeGenerator::Context context = cg.getContext(); FunctionScopePtr funcScope = m_funcScope.lock(); string fname = funcScope->getId(cg).c_str(); bool pseudoMain = funcScope->inPseudoMain(); string origFuncName = !pseudoMain ? funcScope->getOriginalName() : ("run_init::" + funcScope->getFileScope()->getName()); string funcSection; if (outputFFI(cg, ar)) return; if (context == CodeGenerator::NoContext) { string rname = cg.formatLabel(m_name); if (funcScope->isRedeclaring()) { cg.printf("g->%s%s = &%s%s;\n", Option::CallInfoPrefix, m_name.c_str(), Option::CallInfoPrefix, fname.c_str()); } if (funcScope->isVolatile()) { cg_printf("g->declareFunctionLit("); cg_printString(m_name, ar); cg_printf(");\n"); cg_printf("g->FVF(%s) = true;\n", rname.c_str()); } return; } if (context == CodeGenerator::CppDeclaration && !funcScope->isInlined()) return; if (context == CodeGenerator::CppPseudoMain && !pseudoMain) return; if (context == CodeGenerator::CppImplementation && (funcScope->isInlined() || pseudoMain)) return; ar->pushScope(funcScope); cg.setPHPLineNo(-1); if (pseudoMain && !Option::GenerateCPPMain) { if (context == CodeGenerator::CppPseudoMain) { if (cg.getOutput() != CodeGenerator::SystemCPP) { cg.setContext(CodeGenerator::NoContext); // no inner functions/classes funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal); outputCPPStmt(cg, ar); funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal); cg.setContext(CodeGenerator::CppPseudoMain); ar->popScope(); return; } } else if (context == CodeGenerator::CppForwardDeclaration && cg.getOutput() != CodeGenerator::SystemCPP) { return; } } if (context == CodeGenerator::CppImplementation) { printSource(cg); } else if (context == CodeGenerator::CppForwardDeclaration && Option::GenerateCppLibCode) { cg_printf("\n"); printSource(cg); cg.printDocComment(funcScope->getDocComment()); } if (funcScope->isInlined()) cg_printf("inline "); TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg_printf("void"); } funcSection = Option::FunctionSections[origFuncName]; if (!funcSection.empty()) { cg_printf(" __attribute__ ((section (\".text.%s\")))", funcSection.c_str()); } if (pseudoMain) { cg_printf(" %s%s(", Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { cg_printf(" %s%s(", Option::FunctionPrefix, fname.c_str()); } switch (context) { case CodeGenerator::CppForwardDeclaration: funcScope->outputCPPParamsDecl(cg, ar, m_params, true); cg_printf(");\n"); if (funcScope->hasDirectInvoke()) { cg_printf("Variant %s%s(void *extra, CArrRef params);\n", Option::InvokePrefix, fname.c_str()); } break; case CodeGenerator::CppDeclaration: case CodeGenerator::CppImplementation: case CodeGenerator::CppPseudoMain: { funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg_indentBegin(") {\n"); const char *sys = (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : ""); if (pseudoMain) { cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n", sys, origFuncName.c_str(), Option::PseudoMainPrefix, funcScope->getFileScope()->pseudoMainName().c_str()); } else { if (m_stmt->hasBody()) { cg_printf("FUNCTION_INJECTION%s(%s);\n", sys, origFuncName.c_str()); } outputCPPArgInjections(cg, ar, origFuncName.c_str(), ClassScopePtr(), funcScope); } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes outputCPPStmt(cg, ar); cg.setContext(context); cg_indentEnd("} /* function */\n"); } break; default: ASSERT(false); } ar->popScope(); }
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(); }