2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/compiler/option.h"
18 #include "hphp/compiler/analysis/analysis_result.h"
19 #include "hphp/compiler/analysis/file_scope.h"
20 #include "hphp/compiler/analysis/class_scope.h"
21 #include "hphp/compiler/analysis/variable_table.h"
22 #include "hphp/parser/scanner.h"
23 #include "hphp/util/logger.h"
24 #include "hphp/util/db-query.h"
25 #include "hphp/util/util.h"
26 #include "hphp/util/process.h"
27 #include <boost/algorithm/string/trim.hpp>
28 #include "hphp/runtime/base/preg.h"
36 ///////////////////////////////////////////////////////////////////////////////
38 std::string
Option::SystemRoot
;
39 std::string
Option::RootDirectory
;
40 set
<string
> Option::PackageDirectories
;
41 set
<string
> Option::PackageFiles
;
42 set
<string
> Option::PackageExcludeDirs
;
43 set
<string
> Option::PackageExcludeFiles
;
44 set
<string
> Option::PackageExcludePatterns
;
45 set
<string
> Option::PackageExcludeStaticDirs
;
46 set
<string
> Option::PackageExcludeStaticFiles
;
47 set
<string
> Option::PackageExcludeStaticPatterns
;
48 bool Option::CachePHPFile
= false;
50 vector
<string
> Option::ParseOnDemandDirs
;
52 map
<string
, string
> Option::IncludeRoots
;
53 map
<string
, string
> Option::AutoloadRoots
;
54 vector
<string
> Option::IncludeSearchPaths
;
55 string
Option::DefaultIncludeRoot
;
56 map
<string
, int> Option::DynamicFunctionCalls
;
58 bool Option::GeneratePickledPHP
= false;
59 bool Option::GenerateInlinedPHP
= false;
60 bool Option::GenerateTrimmedPHP
= false;
61 bool Option::GenerateInferredTypes
= false;
62 bool Option::ConvertSuperGlobals
= false;
63 bool Option::ConvertQOpExpressions
= false;
64 string
Option::ProgramPrologue
;
65 string
Option::TrimmedPrologue
;
66 vector
<string
> Option::DynamicFunctionPrefixes
;
67 vector
<string
> Option::DynamicFunctionPostfixes
;
68 vector
<string
> Option::DynamicMethodPrefixes
;
69 vector
<string
> Option::DynamicMethodPostfixes
;
70 vector
<string
> Option::DynamicClassPrefixes
;
71 vector
<string
> Option::DynamicClassPostfixes
;
72 set
<string
> Option::DynamicInvokeFunctions
;
73 set
<string
> Option::VolatileClasses
;
74 map
<string
,string
> Option::AutoloadClassMap
;
75 map
<string
,string
> Option::AutoloadFuncMap
;
76 map
<string
,string
> Option::AutoloadConstMap
;
77 string
Option::AutoloadRoot
;
79 map
<string
, string
> Option::FunctionSections
;
81 bool Option::GenerateTextHHBC
= false;
82 bool Option::GenerateBinaryHHBC
= false;
83 string
Option::RepoCentralPath
;
84 bool Option::RepoDebugInfo
= false;
86 string
Option::IdPrefix
= "$$";
87 string
Option::LabelEscape
= "$";
89 string
Option::LambdaPrefix
= "df_";
90 string
Option::Tab
= " ";
92 const char *Option::UserFilePrefix
= "php/";
93 const char *Option::ClassHeaderPrefix
= "cls/";
95 bool Option::PreOptimization
= false;
96 bool Option::PostOptimization
= false;
97 bool Option::SeparateCompilation
= false;
98 bool Option::SeparateCompLib
= false;
99 bool Option::AnalyzePerfectVirtuals
= true;
100 bool Option::HardTypeHints
= true;
102 bool Option::KeepStatementsWithNoEffect
= false;
104 int Option::ConditionalIncludeExpandLevel
= 1;
106 int Option::DependencyMaxProgram
= 1;
107 int Option::CodeErrorMaxProgram
= 1;
109 Option::EvalLevel
Option::EnableEval
= NoEval
;
111 std::string
Option::ProgramName
;
113 bool Option::ParseTimeOpts
= true;
114 bool Option::EnableHipHopSyntax
= false;
115 bool Option::EnableZendCompat
= false;
116 bool Option::JitEnableRenameFunction
= false;
117 bool Option::EnableHipHopExperimentalSyntax
= false;
118 bool Option::EnableShortTags
= true;
119 bool Option::EnableAspTags
= false;
120 bool Option::EnableXHP
= false;
121 bool Option::EnableFinallyStatement
= false;
122 int Option::ParserThreadCount
= 0;
124 int Option::GetScannerType() {
126 if (EnableShortTags
) type
|= Scanner::AllowShortTags
;
127 if (EnableAspTags
) type
|= Scanner::AllowAspTags
;
128 if (EnableXHP
) type
|= Scanner::AllowXHPSyntax
;
129 if (EnableHipHopSyntax
) type
|= Scanner::AllowHipHopSyntax
;
133 int Option::InvokeFewArgsCount
= 6;
134 int Option::InlineFunctionThreshold
= -1;
135 bool Option::EliminateDeadCode
= true;
136 bool Option::CopyProp
= false;
137 bool Option::LocalCopyProp
= true;
138 bool Option::StringLoopOpts
= true;
139 int Option::AutoInline
= 0;
140 bool Option::ControlFlow
= true;
141 bool Option::VariableCoalescing
= false;
142 bool Option::ArrayAccessIdempotent
= false;
143 bool Option::DumpAst
= false;
144 bool Option::WholeProgram
= true;
145 bool Option::RecordErrors
= true;
146 std::string
Option::DocJson
;
148 bool Option::AllDynamic
= true;
149 bool Option::AllVolatile
= false;
151 StringBag
Option::OptionStrings
;
153 bool Option::GenerateDocComments
= true;
155 void (*Option::m_hookHandler
)(Hdf
&config
);
156 bool (*Option::PersistenceHook
)(BlockScopeRawPtr scope
, FileScopeRawPtr file
);
158 ///////////////////////////////////////////////////////////////////////////////
159 // load from a PHP file
161 std::string
Option::GetSystemRoot() {
162 if (SystemRoot
.empty()) {
163 const char *home
= getenv("HPHP_HOME");
164 if (!home
|| !*home
) {
165 throw Exception("Environment variable HPHP_HOME is not set, "
166 "and neither is the SystemRoot option.");
169 SystemRoot
+= "/hphp";
174 ///////////////////////////////////////////////////////////////////////////////
175 // load from HDF file
177 void Option::LoadRootHdf(const Hdf
&roots
, map
<string
, string
> &map
) {
178 if (roots
.exists()) {
179 for (Hdf hdf
= roots
.firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
180 map
[hdf
["root"].get()] = hdf
["path"].get();
185 void Option::LoadRootHdf(const Hdf
&roots
, vector
<string
> &vec
) {
186 if (roots
.exists()) {
187 for (Hdf hdf
= roots
.firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
188 vec
.push_back(hdf
.getString(""));
193 void Option::Load(Hdf
&config
) {
194 LoadRootHdf(config
["IncludeRoots"], IncludeRoots
);
195 LoadRootHdf(config
["AutoloadRoots"], AutoloadRoots
);
197 config
["PackageFiles"].get(PackageFiles
);
198 config
["IncludeSearchPaths"].get(IncludeSearchPaths
);
199 config
["PackageDirectories"].get(PackageDirectories
);
200 config
["PackageExcludeDirs"].get(PackageExcludeDirs
);
201 config
["PackageExcludeFiles"].get(PackageExcludeFiles
);
202 config
["PackageExcludePatterns"].get(PackageExcludePatterns
);
203 config
["PackageExcludeStaticDirs"].get(PackageExcludeStaticDirs
);
204 config
["PackageExcludeStaticFiles"].get(PackageExcludeStaticFiles
);
205 config
["PackageExcludeStaticPatterns"].get(PackageExcludeStaticPatterns
);
206 CachePHPFile
= config
["CachePHPFile"].getBool();
208 config
["ParseOnDemandDirs"].get(ParseOnDemandDirs
);
211 Hdf cg
= config
["CodeGeneration"];
214 #define READ_CG_OPTION(name) \
215 tmp = cg[#name].getString(); \
216 if (!tmp.empty()) { \
217 name = OptionStrings.add(tmp.c_str()); \
220 READ_CG_OPTION(IdPrefix
);
221 READ_CG_OPTION(LabelEscape
);
222 READ_CG_OPTION(LambdaPrefix
);
225 config
["DynamicFunctionPrefix"].get(DynamicFunctionPrefixes
);
226 config
["DynamicFunctionPostfix"].get(DynamicFunctionPostfixes
);
227 config
["DynamicMethodPrefix"].get(DynamicMethodPrefixes
);
228 config
["DynamicInvokeFunctions"].get(DynamicInvokeFunctions
);
229 config
["VolatileClasses"].get(VolatileClasses
);
231 // build map from function names to sections
232 for (Hdf hdf
= config
["FunctionSections"].firstChild(); hdf
.exists();
234 for (Hdf hdfFunc
= hdf
.firstChild(); hdfFunc
.exists();
235 hdfFunc
= hdfFunc
.next()) {
236 FunctionSections
[hdfFunc
.getString()] = hdf
.getName();
241 Hdf repo
= config
["Repo"];
243 Hdf repoCentral
= repo
["Central"];
244 RepoCentralPath
= repoCentral
["Path"].getString();
246 RepoDebugInfo
= repo
["DebugInfo"].getBool(false);
250 Hdf autoloadMap
= config
["AutoloadMap"];
251 autoloadMap
["class"].get(AutoloadClassMap
);
252 autoloadMap
["function"].get(AutoloadFuncMap
);
253 autoloadMap
["constant"].get(AutoloadConstMap
);
254 AutoloadRoot
= autoloadMap
["root"].getString();
257 HardTypeHints
= config
["HardTypeHints"].getBool(true);
259 EnableHipHopSyntax
= config
["EnableHipHopSyntax"].getBool();
260 EnableZendCompat
= config
["EnableZendCompat"].getBool();
261 JitEnableRenameFunction
= config
["JitEnableRenameFunction"].getBool();
262 EnableHipHopExperimentalSyntax
=
263 config
["EnableHipHopExperimentalSyntax"].getBool();
264 EnableShortTags
= config
["EnableShortTags"].getBool(true);
266 EnableAspTags
= config
["EnableAspTags"].getBool();
268 EnableXHP
= config
["EnableXHP"].getBool(false);
270 if (EnableHipHopSyntax
) {
271 // If EnableHipHopSyntax is true, it forces EnableXHP to true
272 // regardless of how it was set in the config
276 ParserThreadCount
= config
["ParserThreadCount"].getInt32(0);
277 if (ParserThreadCount
<= 0) {
278 ParserThreadCount
= Process::GetCPUCount();
281 EnableFinallyStatement
= config
["EnableFinallyStatement"].getBool();
283 EnableEval
= (EvalLevel
)config
["EnableEval"].getByte(0);
284 AllDynamic
= config
["AllDynamic"].getBool(true);
285 AllVolatile
= config
["AllVolatile"].getBool();
287 GenerateDocComments
= config
["GenerateDocComments"].getBool(true);
288 EliminateDeadCode
= config
["EliminateDeadCode"].getBool(true);
289 CopyProp
= config
["CopyProp"].getBool(false);
290 LocalCopyProp
= config
["LocalCopyProp"].getBool(true);
291 StringLoopOpts
= config
["StringLoopOpts"].getBool(true);
292 AutoInline
= config
["AutoInline"].getInt32(0);
293 ControlFlow
= config
["ControlFlow"].getBool(true);
294 VariableCoalescing
= config
["VariableCoalescing"].getBool(false);
295 ArrayAccessIdempotent
= config
["ArrayAccessIdempotent"].getBool(false);
296 DumpAst
= config
["DumpAst"].getBool(false);
297 WholeProgram
= config
["WholeProgram"].getBool(true);
299 // Temporary, during file-cache migration.
300 FileCache::UseNewCache
= config
["UseNewCache"].getBool(false);
302 if (m_hookHandler
) m_hookHandler(config
);
307 void Option::Load() {
311 void Option::OnLoad() {
312 // all lambda functions are dynamic automatically
313 DynamicFunctionPrefixes
.push_back(LambdaPrefix
);
316 ///////////////////////////////////////////////////////////////////////////////
318 bool Option::IsDynamicFunction(bool method
, const std::string
&name
) {
320 return IsDynamic(name
, DynamicMethodPrefixes
, DynamicMethodPostfixes
);
322 return IsDynamic(name
, DynamicFunctionPrefixes
, DynamicFunctionPostfixes
);
325 bool Option::IsDynamicClass(const std::string
&name
) {
326 return IsDynamic(name
, DynamicClassPrefixes
, DynamicClassPostfixes
);
329 bool Option::IsDynamic(const std::string
&name
,
330 const std::vector
<std::string
> &prefixes
,
331 const std::vector
<std::string
> &postfixes
) {
332 if (name
.substr(0, 4) == "dyn_") return true;
334 for (unsigned int i
= 0; i
< prefixes
.size(); i
++) {
335 const string
&prefix
= prefixes
[i
];
336 if (name
.substr(0, prefix
.length()) == prefix
) {
341 for (unsigned int i
= 0; i
< postfixes
.size(); i
++) {
342 const string
&postfix
= postfixes
[i
];
343 if (name
.length() > postfix
.length() &&
344 name
.substr(name
.length() - postfix
.length()) == postfix
) {
352 std::string
Option::GetAutoloadRoot(const std::string
&name
) {
353 for (map
<string
, string
>::const_iterator iter
= AutoloadRoots
.begin();
354 iter
!= AutoloadRoots
.end(); ++iter
) {
355 if (name
.substr(0, iter
->first
.length()) == iter
->first
) {
362 std::string
Option::MangleFilename(const std::string
&name
, bool id
) {
363 string ret
= UserFilePrefix
;
367 Util::replaceAll(ret
, "/", "$");
368 Util::replaceAll(ret
, "-", "_");
369 Util::replaceAll(ret
, ".", "_");
374 bool Option::IsFileExcluded(const std::string
&file
,
375 const std::set
<std::string
> &patterns
) {
376 String
sfile(file
.c_str(), file
.size(), CopyString
);
377 for (set
<string
>::const_iterator iter
= patterns
.begin();
378 iter
!= patterns
.end(); ++iter
) {
379 const std::string
&pattern
= *iter
;
381 Variant ret
= preg_match(String(pattern
.c_str(), pattern
.size(),
382 CopyString
), sfile
, matches
);
383 if (ret
.toInt64() > 0) {
390 void Option::FilterFiles(std::vector
<std::string
> &files
,
391 const std::set
<std::string
> &patterns
) {
392 for (int i
= files
.size() - 1; i
>= 0; i
--) {
393 if (IsFileExcluded(files
[i
], patterns
)) {
394 files
.erase(files
.begin() + i
);