void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar, StringToFunctionScopePtrMap &map, ClassInfo *cls) { const ClassInfo::MethodVec &methods = cls->getMethodsVec(); for (auto it = methods.begin(); it != methods.end(); ++it) { FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it); assert(!map[f->getName()]); map[f->getName()] = f; } }
void BuiltinSymbols::ParseExtFunctions(AnalysisResultPtr ar, const char **p, bool sep) { while (*p) { FunctionScopePtr f = ParseExtFunction(ar, p); if (sep) { f->setSepExtension(); } assert(!s_functions[f->getName()]); s_functions[f->getName()] = f; } }
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; stmt->outputCPP(cg, ar); if (stmt->is(Statement::KindOfMethodStatement)) { MethodStatementPtr methodStmt = dynamic_pointer_cast<MethodStatement>(stmt); std::string methodName = methodStmt->getName(); if (methodName == "offsetget") { ClassScopePtr cls = getClassScope(); std::string arrayAccess("arrayaccess"); if (cls->derivesFrom(ar, arrayAccess, false, false)) { FunctionScopePtr funcScope = methodStmt->getFunctionScope(); std::string name = funcScope->getName(); funcScope->setName("__offsetget_lval"); methodStmt->setName("__offsetget_lval"); methodStmt->outputCPP(cg, ar); funcScope->setName(name); methodStmt->setName("offsetget"); } } } } }
void StatementList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr func = getFunctionScope(); bool inPseudoMain = func && func->inPseudoMain(); std::vector<bool> isDeclaration; if (inPseudoMain) { // We need these declarations to go first, because PHP allows top level // function and class declarations to appear after usage. for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; bool isDecl = false; if (stmt->is(Statement::KindOfFunctionStatement)) { isDecl = true; } else if (stmt->is(Statement::KindOfClassStatement) || stmt->is(Statement::KindOfInterfaceStatement)) { ClassScopePtr cls = (dynamic_pointer_cast<InterfaceStatement>(stmt))->getClassScope(); isDecl = cls->isBaseClass() || !cls->isVolatile(); } if (isDecl) stmt->outputCPP(cg,ar); isDeclaration.push_back(isDecl); } } for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; if (stmt->is(Statement::KindOfClassStatement)) { if (!inPseudoMain || !isDeclaration[i]) stmt->outputCPP(cg, ar); } else if (!(stmt->is(Statement::KindOfFunctionStatement) || stmt->is(Statement::KindOfInterfaceStatement)) || (!inPseudoMain || !isDeclaration[i])) { stmt->outputCPP(cg, ar); if (stmt->is(Statement::KindOfMethodStatement)) { MethodStatementPtr methodStmt = dynamic_pointer_cast<MethodStatement>(stmt); std::string methodName = methodStmt->getName(); if (methodName == "offsetget") { ClassScopePtr cls = getClassScope(); std::string arrayAccess("arrayaccess"); if (cls->derivesFrom(ar, arrayAccess, false, false)) { FunctionScopePtr funcScope = methodStmt->getFunctionScope(); std::string name = funcScope->getName(); funcScope->setName("__offsetget_lval"); methodStmt->setName("__offsetget_lval"); methodStmt->outputCPP(cg, ar); funcScope->setName(name); methodStmt->setName("offsetget"); } } } } } }
bool ClassScope::addFunction(AnalysisResultConstPtr ar, FunctionScopePtr funcScope) { FunctionScopePtr &func = m_functions[funcScope->getName()]; if (func) { func->getStmt()->parseTimeFatal(Compiler::DeclaredMethodTwice, "Redeclared method %s::%s", getOriginalName().c_str(), func->getOriginalName().c_str()); } func = funcScope; m_functionsVec.push_back(funcScope); return true; }
void ParameterExpression::analyzeProgram(AnalysisResultPtr ar) { if (!m_type.empty()) addUserClass(ar, m_type); if (m_defaultValue) m_defaultValue->analyzeProgram(ar); if (ar->isFirstPass()) { // Have to use non const ref params for magic methods FunctionScopePtr fs = ar->getFunctionScope(); if (fs->isMagicMethod() || fs->getName() == "offsetget") { fs->getVariables()->addLvalParam(m_name); } } }
bool FileScope::addFunction(AnalysisResultConstPtr ar, FunctionScopePtr funcScope) { if (ar->declareFunction(funcScope)) { FunctionScopePtr &fs = m_functions[funcScope->getName()]; if (fs) { if (!m_redeclaredFunctions) { m_redeclaredFunctions = new StringToFunctionScopePtrVecMap; } FunctionScopePtrVec &funcVec = (*m_redeclaredFunctions)[funcScope->getName()]; if (!funcVec.size()) { fs->setLocalRedeclaring(); funcVec.push_back(fs); } funcScope->setLocalRedeclaring(); funcVec.push_back(funcScope); } else { fs = funcScope; } return true; } return false; }
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"); }
bool AnalysisResult::declareFunction(FunctionScopePtr funcScope) const { assert(m_phase < AnalyzeAll); string fname = funcScope->getName(); // System functions override auto it = m_functions.find(fname); if (it != m_functions.end()) { if (!it->second->allowOverride()) { // we need someone to hold on to a reference to it // even though we're not going to do anything with it this->lock()->m_ignoredScopes.push_back(funcScope); return false; } } return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) { if (Loaded) return true; Loaded = true; // Build function scopes for some of the runtime helper functions // declared in "runtime/base/builtin_functions.h" const char **helper = HelperFunctions; while (*helper) { FunctionScopePtr f = ParseHelperFunction(ar, helper); ASSERT(!s_helperFunctions[f->getName()]); s_helperFunctions[f->getName()] = f; } // load extension functions first, so system/classes may call them ParseExtFunctions(ar, ExtensionFunctions, false); AnalysisResultPtr ar2; // parse all PHP files under system/classes if (!extOnly) { ar = AnalysisResultPtr(new AnalysisResult()); ar->loadBuiltinFunctions(); for (const char **cls = SystemClasses; *cls; cls++) { string phpBaseName = "/system/classes/"; phpBaseName += *cls; phpBaseName += ".php"; string phpFileName = Option::GetSystemRoot() + phpBaseName; const char *baseName = s_strings.add(phpBaseName.c_str()); const char *fileName = s_strings.add(phpFileName.c_str()); try { Scanner scanner(fileName, Option::ScannerType); Compiler::Parser parser(scanner, baseName, ar); if (!parser.parse()) { Logger::Error("Unable to parse file %s: %s", fileName, parser.getMessage().c_str()); ASSERT(false); } } catch (FileOpenException &e) { Logger::Error("%s", e.getMessage().c_str()); } } ar->analyzeProgram(true); ar->inferTypes(); const StringToFileScopePtrMap &files = ar->getAllFiles(); for (StringToFileScopePtrMap::const_iterator iterFile = files.begin(); iterFile != files.end(); iterFile++) { const StringToClassScopePtrVecMap &classes = iterFile->second->getClasses(); for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(); iter != classes.end(); ++iter) { ASSERT(iter->second.size() == 1); iter->second[0]->setSystem(); ASSERT(!s_classes[iter->first]); s_classes[iter->first] = iter->second[0]; } } // parse globals/variables.php and globals/constants.php NoSuperGlobals = true; s_variables = LoadGlobalSymbols("symbols.php")->getVariables(); ar2 = LoadGlobalSymbols("constants.php"); const FileScopePtrVec &fileScopes = ar2->getAllFilesVector(); if (!fileScopes.empty()) { s_constants = fileScopes[0]->getConstants(); } else { Logger::Error("Couldn't load constants.php"); return false; } NoSuperGlobals = false; } else { ar2 = AnalysisResultPtr(new AnalysisResult()); s_variables = VariableTablePtr(new VariableTable(*ar2.get())); s_constants = ConstantTablePtr(new ConstantTable(*ar2.get())); NoSuperGlobals = true; } s_constants->setDynamic(ar, "SID", true); // load extension constants, classes and dynamics ParseExtConsts(ar, ExtensionConsts, false); ParseExtClasses(ar, ExtensionClasses, false); for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) { Option::SepExtensionOptions &options = Option::SepExtensions[i]; string soname = options.soname; if (soname.empty()) { soname = string("lib") + options.name + ".so"; } if (!options.lib_path.empty()) { soname = options.lib_path + "/" + soname; } if (!LoadSepExtensionSymbols(ar, options.name, soname)) { return false; } } return true; }
void MethodStatement::outputCPPFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr clsScope = getClassScope(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); string fname = funcScope->getId(cg); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); if (inClass && m_modifiers->isAbstract()) { return; } if (funcScope->getName() == "__offsetget_lval") { return; } if (ret) { cg_printf("int"); } else { cg_printf("void"); } cg_printf(" %s%s%s(", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); if (ret) { cg_printf("void** res"); } bool first = !ret; if (!isStatic) { // instance methods need one additional parameter for the target if (first) { first = false; } else { cg_printf(", "); } cg_printf("Variant *target"); } int ac = funcScope->getMaxParamCount(); for (int i = 0; i < ac; ++i) { if (first) { first = false; } else { cg_printf(", "); } cg_printf("Variant *a%d", i); } if (varArgs) { if (!first) { cg_printf(", "); } cg_printf("Variant *va"); } cg_printf(")"); if (cg.getContext() == CodeGenerator::CppFFIDecl) { cg_printf(";\n"); } else { cg_indentBegin(" {\n"); if (ret) { cg_printf("return hphp_ffi_exportVariant("); } if (!inClass) { // simple function call cg_printf("%s%s(", Option::FunctionPrefix, fname.c_str()); } else if (isStatic) { // static method call cg_printf("%s%s::%s%s(", Option::ClassPrefix, clsScope->getId(cg).c_str(), Option::MethodPrefix, funcScope->getName().c_str()); } else { // instance method call cg_printf("dynamic_cast<%s%s *>(target->getObjectData())->", Option::ClassPrefix, clsScope->getId(cg).c_str()); cg_printf("%s%s(", Option::MethodPrefix, funcScope->getName().c_str()); } first = true; if (varArgs) { cg_printf("%d + (va->isNull() ? 0 : va->getArrayData()->size())", ac); first = false; } for (int i = 0; i < ac; ++i) { if (first) { first = false; } else { cg_printf(", "); } cg_printf("*a%d", i); } if (varArgs) { cg_printf(", va->toArray()"); } if (ret) { cg_printf("), res"); } cg_printf(");\n"); cg_indentEnd("}\n"); cg.printImplSplitter(); } return; }
void MethodStatement::outputJavaFFICPPStub(CodeGenerator &cg, AnalysisResultPtr ar) { // TODO translate PHP namespace once that is supported string packageName = Option::JavaFFIRootPackage; FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); string fname = funcScope->getId(cg); int ac = funcScope->getMaxParamCount(); bool exposeNative = !(ac > 0 || varArgs || !isStatic || !ret && inClass); if (inClass && m_modifiers->isAbstract()) { // skip all the abstract methods, because hphp doesn't generate code // for them return; } if (funcScope->getName() == "__offsetget_lval") return; const char *clsName; if (inClass) { // uses capitalized original class name ClassScopePtr cls = ar->findClass(m_className); clsName = cls->getOriginalName().c_str(); } else { clsName = "HphpMain"; } string mangledName = "Java." + packageName + "." + clsName + "." + fname + (exposeNative ? "" : "_native"); // all the existing "_" are replaced as "_1" Util::replaceAll(mangledName, "_", "_1"); Util::replaceAll(mangledName, ".", "_"); cg_printf("JNIEXPORT %s JNICALL\n", ret ? "jobject" : "void"); cg_printf("%s(JNIEnv *env, %s target", mangledName.c_str(), (isStatic ? "jclass" : "jobject")); ostringstream args; bool first = true; if (!isStatic) { // instance method also gets an additional argument, which is a Variant // pointer to the target, encoded in int64 first = false; cg_printf(", jlong targetPtr"); args << "(Variant *)targetPtr"; } for (int i = 0; i < ac; i++) { cg_printf(", jlong a%d", i); if (first) first = false; else args << ", "; args << "(Variant *)a" << i; } if (varArgs) { cg_printf(", jlong va"); if (!first) args << ", "; args << "(Variant *)va"; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl) { // java_stubs.h cg_printf(");\n\n"); return; } cg_indentBegin(") {\n"); // support static/instance methods if (ret) { cg_printf("void *result;\n"); cg_printf("int kind = "); cg_printf("%s%s%s(&result", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); if (!isStatic || ac > 0 || varArgs) cg_printf(", "); } else { cg_printf("%s%s%s(", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); } cg_printf("%s);\n", args.str().c_str()); if (ret) { if (!inClass) { // HphpMain extends hphp.Hphp. cg_printf("jclass hphp = env->GetSuperclass(target);\n"); } else { cg_printf("jclass hphp = env->FindClass(\"hphp/Hphp\");\n"); } cg_printf("return exportVariantToJava(env, hphp, result, kind);\n"); } cg_indentEnd("}\n"); cg.printImplSplitter(); }
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool linemap = outputLineMap(cg, ar, true); if (!m_lambda.empty()) { cg.printf("\"%s\"", m_lambda.c_str()); if (linemap) cg.printf(")"); return; } if (m_className.empty()) { if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); ExpressionPtr value = (*m_params)[1]; if (varName.empty()) { cg.printf("throw_fatal(\"bad define\")"); } else if (m_dynamicConstant) { cg.printf("g->declareConstant(\"%s\", g->%s%s, ", varName.c_str(), Option::ConstantPrefix, varName.c_str()); value->outputCPP(cg, ar); cg.printf(")"); } else { bool needAssignment = true; bool isSystem = ar->getConstants()->isSystem(varName); if (isSystem || ((!ar->isConstantRedeclared(varName)) && value->isScalar())) { needAssignment = false; } if (needAssignment) { cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str()); value->outputCPP(cg, ar); } } } else { cg.printf("throw_fatal(\"bad define\")"); } if (linemap) cg.printf(")"); return; } if (m_name == "func_num_args") { cg.printf("num_args"); if (linemap) cg.printf(")"); return; } switch (m_type) { case VariableArgumentFunction: { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); if (func) { cg.printf("%s(", m_name.c_str()); func->outputCPPParamsCall(cg, ar, true); if (m_params) { cg.printf(","); m_params->outputCPP(cg, ar); } cg.printf(")"); if (linemap) cg.printf(")"); return; } } break; case FunctionExistsFunction: case ClassExistsFunction: case InterfaceExistsFunction: { bool literalString = false; string symbol; if (m_params && m_params->getCount() == 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { literalString = true; symbol = name->getLiteralString(); } } } if (literalString) { switch (m_type) { case FunctionExistsFunction: { const std::string &lname = Util::toLower(symbol); bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) != Option::DynamicInvokeFunctions.end(); if (!dynInvoke) { FunctionScopePtr func = ar->findFunction(lname); if (func) { if (!func->isDynamic()) { if (func->isRedeclaring()) { const char *name = func->getName().c_str(); cg.printf("(%s->%s%s != invoke_failed_%s)", cg.getGlobals(ar), Option::InvokePrefix, name, name); break; } cg.printf("true"); break; } } else { cg.printf("false"); break; } } cg.printf("f_function_exists(\"%s\")", lname.c_str()); } break; case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && !cls->isInterface()) { const char *name = cls->getName().c_str(); cg.printf("f_class_exists(\"%s\")", name); } else { cg.printf("false"); } } break; case InterfaceExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && cls->isInterface()) { const char *name = cls->getName().c_str(); cg.printf("f_interface_exists(\"%s\")", name); } else { cg.printf("false"); } } break; default: break; } if (linemap) cg.printf(")"); return; } } break; case GetDefinedVarsFunction: cg.printf("get_defined_vars(variables)"); if (linemap) cg.printf(")"); return; default: break; } } outputCPPParamOrderControlled(cg, ar); if (linemap) cg.printf(")"); }
void SimpleFunctionCall::outputCPPParamOrderControlled(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_className.empty()) { switch (m_type) { case ExtractFunction: cg.printf("extract(variables, "); FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false); cg.printf(")"); return; case CompactFunction: cg.printf("compact(variables, "); FunctionScope::outputCPPArguments(m_params, cg, ar, -1, true); cg.printf(")"); return; default: break; } } bool volatileCheck = false; ClassScopePtr cls; if (!m_className.empty()) { cls = ar->findClass(m_className); if (cls && !ar->checkClassPresent(m_origClassName)) { volatileCheck = true; cls->outputVolatileCheckBegin(cg, ar, cls->getOriginalName()); } } if (m_valid) { bool tooManyArgs = (m_params && m_params->outputCPPTooManyArgsPre(cg, ar, m_name)); if (!m_className.empty()) { cg.printf("%s%s::", Option::ClassPrefix, m_className.c_str()); if (m_name == "__construct" && cls) { FunctionScopePtr func = cls->findConstructor(ar, true); cg.printf("%s%s(", Option::MethodPrefix, func->getName().c_str()); } else { cg.printf("%s%s(", Option::MethodPrefix, m_name.c_str()); } } else { int paramCount = m_params ? m_params->getCount() : 0; if (m_name == "get_class" && ar->getClassScope() && paramCount == 0) { cg.printf("(\"%s\"", ar->getClassScope()->getOriginalName()); } else if (m_name == "get_parent_class" && ar->getClassScope() && paramCount == 0) { const std::string parentClass = ar->getClassScope()->getParent(); if (!parentClass.empty()) { cg.printf("(\"%s\"", ar->getClassScope()->getParent().c_str()); } else { cg.printf("(false"); } } else { if (m_noPrefix) { cg.printf("%s(", m_name.c_str()); } else { cg.printf("%s%s(", m_builtinFunction ? Option::BuiltinFunctionPrefix : Option::FunctionPrefix, m_name.c_str()); } } } FunctionScope::outputCPPArguments(m_params, cg, ar, m_extraArg, m_variableArgument, m_argArrayId); cg.printf(")"); if (tooManyArgs) { m_params->outputCPPTooManyArgsPost(cg, ar, m_voidReturn); } } else { if (m_className.empty()) { if (m_redeclared && !m_dynamicInvoke) { if (canInvokeFewArgs()) { cg.printf("%s->%s%s_few_args(", cg.getGlobals(ar), Option::InvokePrefix, m_name.c_str()); int left = Option::InvokeFewArgsCount; if (m_params && m_params->getCount()) { left -= m_params->getCount(); cg.printf("%d, ", m_params->getCount()); FunctionScope::outputCPPArguments(m_params, cg, ar, 0, false); } else { cg.printf("0"); } for (int i = 0; i < left; i++) { cg.printf(", null_variant"); } cg.printf(")"); return; } else { cg.printf("%s->%s%s(", cg.getGlobals(ar), Option::InvokePrefix, m_name.c_str()); } } else { cg.printf("invoke(\"%s\", ", m_name.c_str()); } } else { bool inObj = m_parentClass && ar->getClassScope() && !dynamic_pointer_cast<FunctionScope>(ar->getScope())->isStatic(); if (m_redeclaredClass) { if (inObj) { // parent is redeclared cg.printf("parent->%sinvoke(\"%s\",", Option::ObjectPrefix, m_name.c_str()); } else { cg.printf("%s->%s%s->%sinvoke(\"%s\", \"%s\",", cg.getGlobals(ar), Option::ClassStaticsObjectPrefix, m_className.c_str(), Option::ObjectStaticPrefix, m_className.c_str(), m_name.c_str()); } } else if (m_validClass) { if (inObj) { cg.printf("%s%s::%sinvoke(\"%s\",", Option::ClassPrefix, m_className.c_str(), Option::ObjectPrefix, m_name.c_str()); } else { cg.printf("%s%s::%sinvoke(\"%s\", \"%s\",", Option::ClassPrefix, m_className.c_str(), Option::ObjectStaticPrefix, m_className.c_str(), m_name.c_str()); } } else { cg.printf("invoke_static_method(\"%s\", \"%s\",", m_className.c_str(), m_name.c_str()); } } if ((!m_params) || (m_params->getCount() == 0)) { cg.printf("Array()"); } else { FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false); } bool needHash = true; if (m_className.empty()) { needHash = !(m_redeclared && !m_dynamicInvoke); } else { needHash = m_validClass || m_redeclaredClass; } if (!needHash) { cg.printf(")"); } else { cg.printf(", 0x%.16lXLL)", hash_string_i(m_name.data(), m_name.size())); } } if (volatileCheck) { cls->outputVolatileCheckEnd(cg); } }
void AnalysisResult::analyzeProgram(bool system /* = false */) { AnalysisResultPtr ar = shared_from_this(); getVariables()->forceVariants(ar, VariableTable::AnyVars); getVariables()->setAttribute(VariableTable::ContainsLDynamicVariable); getVariables()->setAttribute(VariableTable::ContainsExtract); getVariables()->setAttribute(VariableTable::ForceGlobal); // Analyze Includes Logger::Verbose("Analyzing Includes"); sort(m_fileScopes.begin(), m_fileScopes.end(), by_filename); // fixed order unsigned int i = 0; for (i = 0; i < m_fileScopes.size(); i++) { collectFunctionsAndClasses(m_fileScopes[i]); } // Keep generated code identical without randomness canonicalizeSymbolOrder(); markRedeclaringClasses(); // Analyze some special cases for (set<string>::const_iterator it = Option::VolatileClasses.begin(); it != Option::VolatileClasses.end(); ++it) { ClassScopePtr cls = findClass(toLower(*it)); if (cls && cls->isUserClass()) { cls->setVolatile(); } } checkClassDerivations(); resolveNSFallbackFuncs(); // Analyze All Logger::Verbose("Analyzing All"); setPhase(AnalysisResult::AnalyzeAll); for (i = 0; i < m_fileScopes.size(); i++) { m_fileScopes[i]->analyzeProgram(ar); } /* Note that cls->collectMethods() can add entries to m_classDecs, which can invalidate iterators. So we have to create an array and then iterate over that. The new entries added to m_classDecs are always empty, so it doesnt matter that we dont include them in the iteration */ std::vector<ClassScopePtr> classes; classes.reserve(m_classDecs.size()); for (StringToClassScopePtrVecMap::const_iterator iter = m_classDecs.begin(); iter != m_classDecs.end(); ++iter) { for (ClassScopePtr cls: iter->second) { classes.push_back(cls); } } // Collect methods for (ClassScopePtr cls: classes) { if (cls->isRedeclaring()) { cls->setStaticDynamic(ar); } StringToFunctionScopePtrMap methods; cls->collectMethods(ar, methods, true /* include privates */); bool needAbstractMethodImpl = (!cls->isAbstract() && !cls->isInterface() && cls->derivesFromRedeclaring() == Derivation::Normal && !cls->getAttribute(ClassScope::UsesUnknownTrait)); for (StringToFunctionScopePtrMap::const_iterator iterMethod = methods.begin(); iterMethod != methods.end(); ++iterMethod) { FunctionScopePtr func = iterMethod->second; if (Option::WholeProgram && !func->hasImpl() && needAbstractMethodImpl) { FunctionScopePtr tmpFunc = cls->findFunction(ar, func->getName(), true, true); always_assert(!tmpFunc || !tmpFunc->hasImpl()); Compiler::Error(Compiler::MissingAbstractMethodImpl, func->getStmt(), cls->getStmt()); } m_methodToClassDecs[iterMethod->first].push_back(cls); } } ClassScopePtr cls; string cname; for (auto& sysclass_cls: m_systemClasses) { tie(cname, cls) = sysclass_cls; StringToFunctionScopePtrMap methods; cls->collectMethods(ar, methods, true /* include privates */); for (StringToFunctionScopePtrMap::const_iterator iterMethod = methods.begin(); iterMethod != methods.end(); ++iterMethod) { m_methodToClassDecs[iterMethod->first].push_back(cls); } } }