2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- 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/builtin_symbols.h"
18 #include "hphp/compiler/analysis/analysis_result.h"
19 #include "hphp/compiler/statement/statement_list.h"
20 #include "hphp/compiler/analysis/type.h"
21 #include "hphp/compiler/analysis/function_scope.h"
22 #include "hphp/compiler/analysis/class_scope.h"
23 #include "hphp/compiler/expression/modifier_expression.h"
24 #include "hphp/compiler/expression/simple_function_call.h"
25 #include "hphp/compiler/option.h"
26 #include "hphp/compiler/parser/parser.h"
27 #include "hphp/compiler/analysis/file_scope.h"
28 #include "hphp/compiler/analysis/variable_table.h"
29 #include "hphp/compiler/analysis/constant_table.h"
30 #include "hphp/util/parser/hphp.tab.hpp"
31 #include "hphp/runtime/base/class_info.h"
32 #include "hphp/runtime/base/program_functions.h"
33 #include "hphp/runtime/base/array/array_iterator.h"
34 #include "hphp/runtime/base/execution_context.h"
35 #include "hphp/runtime/base/thread_init_fini.h"
36 #include "hphp/util/logger.h"
37 #include "hphp/util/util.h"
42 #define BF_COLUMN_COUNT 3
43 #define BF_COLUMN_NAME 0
44 #define BF_COLUMN_RETURN 1
45 #define BF_COLUMN_PARAMS 2
47 #define CLASS_TYPE 999
49 ///////////////////////////////////////////////////////////////////////////////
51 bool BuiltinSymbols::Loaded
= false;
52 bool BuiltinSymbols::NoSuperGlobals
= false;
53 StringBag
BuiltinSymbols::s_strings
;
55 StringToFunctionScopePtrMap
BuiltinSymbols::s_functions
;
57 const char *const BuiltinSymbols::GlobalNames
[] = {
69 "http_response_header",
72 const char *BuiltinSymbols::SystemClasses
[] = {
90 StringToClassScopePtrMap
BuiltinSymbols::s_classes
;
91 VariableTablePtr
BuiltinSymbols::s_variables
;
92 ConstantTablePtr
BuiltinSymbols::s_constants
;
93 StringToTypePtrMap
BuiltinSymbols::s_superGlobals
;
94 void *BuiltinSymbols::s_handle_main
= nullptr;
96 ///////////////////////////////////////////////////////////////////////////////
98 int BuiltinSymbols::NumGlobalNames() {
99 return sizeof(BuiltinSymbols::GlobalNames
) /
100 sizeof(BuiltinSymbols::GlobalNames
[0]);
103 static TypePtr
typePtrFromDataType(DataType dt
, TypePtr unknown
) {
105 case KindOfNull
: return Type::Null
;
106 case KindOfBoolean
: return Type::Boolean
;
107 case KindOfInt64
: return Type::Int64
;
108 case KindOfDouble
: return Type::Double
;
109 case KindOfString
: return Type::String
;
110 case KindOfArray
: return Type::Array
;
111 case KindOfObject
: return Type::Object
;
118 FunctionScopePtr
BuiltinSymbols::ImportFunctionScopePtr(AnalysisResultPtr ar
,
119 ClassInfo
*cls
, ClassInfo::MethodInfo
*method
) {
120 int attrs
= method
->attribute
;
121 bool isMethod
= cls
!= ClassInfo::GetSystem();
122 FunctionScopePtr
f(new FunctionScope(isMethod
,
124 attrs
& ClassInfo::IsReference
));
126 int reqCount
= 0, totalCount
= 0;
127 for(auto it
= method
->parameters
.begin();
128 it
!= method
->parameters
.end(); ++it
) {
129 const ClassInfo::ParameterInfo
*pinfo
= *it
;
130 if (!pinfo
->value
|| !pinfo
->value
[0]) {
135 f
->setParamCounts(ar
, reqCount
, totalCount
);
138 for(auto it
= method
->parameters
.begin();
139 it
!= method
->parameters
.end(); ++it
, ++idx
) {
140 const ClassInfo::ParameterInfo
*pinfo
= *it
;
141 f
->setParamName(idx
, pinfo
->name
);
142 if (pinfo
->attribute
& ClassInfo::IsReference
) {
145 f
->setParamType(ar
, idx
, typePtrFromDataType(pinfo
->argType
, Type::Any
));
146 if (pinfo
->valueLen
) {
147 f
->setParamDefault(idx
, pinfo
->value
, pinfo
->valueLen
,
148 std::string(pinfo
->valueText
, pinfo
->valueTextLen
));
152 if (method
->returnType
!= KindOfNull
) {
153 f
->setReturnType(ar
, typePtrFromDataType(method
->returnType
,
157 f
->setClassInfoAttribute(attrs
);
158 if (attrs
& ClassInfo::HasDocComment
) {
159 f
->setDocComment(method
->docComment
);
162 if (!isMethod
&& (attrs
& ClassInfo::HasOptFunction
)) {
163 // Legacy optimization functions
164 if (method
->name
.same("fb_call_user_func_safe") ||
165 method
->name
.same("fb_call_user_func_safe_return") ||
166 method
->name
.same("fb_call_user_func_array_safe")) {
167 f
->setOptFunction(hphp_opt_fb_call_user_func
);
168 } else if (method
->name
.same("is_callable")) {
169 f
->setOptFunction(hphp_opt_is_callable
);
170 } else if (method
->name
.same("call_user_func_array")) {
171 f
->setOptFunction(hphp_opt_call_user_func
);
176 if (attrs
& ClassInfo::IsProtected
) {
177 f
->addModifier(T_PROTECTED
);
178 } else if (attrs
& ClassInfo::IsPrivate
) {
179 f
->addModifier(T_PRIVATE
);
181 if (attrs
& ClassInfo::IsStatic
) {
182 f
->addModifier(T_STATIC
);
186 // This block of code is not needed, if BlockScope directly takes flags.
187 if (attrs
& ClassInfo::MixedVariableArguments
) {
188 f
->setVariableArgument(-1);
189 } else if (attrs
& ClassInfo::RefVariableArguments
) {
190 f
->setVariableArgument(1);
191 } else if (attrs
& ClassInfo::VariableArguments
) {
192 f
->setVariableArgument(0);
194 if (attrs
& ClassInfo::NoEffect
) {
197 if (attrs
& ClassInfo::FunctionIsFoldable
) {
200 if (attrs
& ClassInfo::ContextSensitive
) {
201 f
->setContextSensitive(true);
203 if (attrs
& ClassInfo::NeedsActRec
) {
206 if ((attrs
& ClassInfo::AllowOverride
) && !isMethod
) {
207 f
->setAllowOverride();
210 FunctionScope::RecordFunctionInfo(f
->getName(), f
);
214 void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar
,
215 StringToFunctionScopePtrMap
&map
,
217 const ClassInfo::MethodVec
&methods
= cls
->getMethodsVec();
218 for (auto it
= methods
.begin(); it
!= methods
.end(); ++it
) {
219 FunctionScopePtr f
= ImportFunctionScopePtr(ar
, cls
, *it
);
220 assert(!map
[f
->getName()]);
221 map
[f
->getName()] = f
;
225 void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar
,
226 FunctionScopePtrVec
&vec
,
228 const ClassInfo::MethodVec
&methods
= cls
->getMethodsVec();
229 for (auto it
= methods
.begin(); it
!= methods
.end(); ++it
) {
230 FunctionScopePtr f
= ImportFunctionScopePtr(ar
, cls
, *it
);
235 void BuiltinSymbols::ImportExtProperties(AnalysisResultPtr ar
,
236 VariableTablePtr dest
,
238 ClassInfo::PropertyVec src
= cls
->getPropertiesVec();
239 for (auto it
= src
.begin(); it
!= src
.end(); ++it
) {
240 ClassInfo::PropertyInfo
*pinfo
= *it
;
241 int attrs
= pinfo
->attribute
;
242 ModifierExpressionPtr
modifiers(
243 new ModifierExpression(BlockScopePtr(), LocationPtr()));
244 if (attrs
& ClassInfo::IsPrivate
) {
245 modifiers
->add(T_PRIVATE
);
246 } else if (attrs
& ClassInfo::IsProtected
) {
247 modifiers
->add(T_PROTECTED
);
249 if (attrs
& ClassInfo::IsStatic
) {
250 modifiers
->add(T_STATIC
);
253 dest
->add(pinfo
->name
.data(),
254 typePtrFromDataType(pinfo
->type
, Type::Variant
),
255 false, ar
, ExpressionPtr(), modifiers
);
259 void BuiltinSymbols::ImportExtConstants(AnalysisResultPtr ar
,
260 ConstantTablePtr dest
,
262 ClassInfo::ConstantVec src
= cls
->getConstantsVec();
263 for (auto it
= src
.begin(); it
!= src
.end(); ++it
) {
264 // We make an assumption that if the constant is a callback type
265 // (e.g. STDIN, STDOUT, STDERR) then it will return an Object.
266 // And that if it's deferred (SID) it'll be a String.
267 ClassInfo::ConstantInfo
*cinfo
= *it
;
268 dest
->add(cinfo
->name
.data(),
269 cinfo
->isDeferred() ?
270 (cinfo
->isCallback() ? Type::Object
: Type::String
) :
271 typePtrFromDataType(cinfo
->getValue().getType(), Type::Variant
),
272 ExpressionPtr(), ar
, ConstructPtr());
276 ClassScopePtr
BuiltinSymbols::ImportClassScopePtr(AnalysisResultPtr ar
,
278 FunctionScopePtrVec methods
;
279 ImportExtFunctions(ar
, methods
, cls
);
281 ClassInfo::InterfaceVec ifaces
= cls
->getInterfacesVec();
282 String parent
= cls
->getParentClass();
283 std::vector
<std::string
> stdIfaces
;
284 if (!parent
.empty() && (ifaces
.empty() || ifaces
[0] != parent
)) {
285 stdIfaces
.push_back(parent
.data());
287 for (auto it
= ifaces
.begin(); it
!= ifaces
.end(); ++it
) {
288 stdIfaces
.push_back(it
->data());
291 ClassScopePtr
cl(new ClassScope(ar
, cls
->getName().data(), parent
.data(),
292 stdIfaces
, methods
));
293 for (uint i
= 0; i
< methods
.size(); ++i
) {
294 methods
[i
]->setOuterScope(cl
);
297 ImportExtProperties(ar
, cl
->getVariables(), cls
);
298 ImportExtConstants(ar
, cl
->getConstants(), cls
);
299 int attrs
= cls
->getAttribute();
300 cl
->setClassInfoAttribute(attrs
);
301 if (attrs
& ClassInfo::HasDocComment
) {
302 cl
->setDocComment(cls
->getDocComment());
308 void BuiltinSymbols::ImportExtClasses(AnalysisResultPtr ar
) {
309 const ClassInfo::ClassMap
&classes
= ClassInfo::GetClassesMap();
310 for (auto it
= classes
.begin(); it
!= classes
.end(); ++it
) {
311 ClassScopePtr cl
= ImportClassScopePtr(ar
, it
->second
);
312 assert(!s_classes
[cl
->getName()]);
313 s_classes
[cl
->getName()] = cl
;
317 bool BuiltinSymbols::Load(AnalysisResultPtr ar
, bool extOnly
/* = false */) {
318 if (Loaded
) return true;
321 if (g_context
.isNull()) init_thread_locals();
324 // load extension functions first, so system/classes may call them
325 ImportExtFunctions(ar
, s_functions
, ClassInfo::GetSystem());
326 AnalysisResultPtr ar2
= AnalysisResultPtr(new AnalysisResult());
327 s_variables
= VariableTablePtr(new VariableTable(*ar2
.get()));
328 s_constants
= ConstantTablePtr(new ConstantTable(*ar2
.get()));
330 // parse all PHP files under system/classes
332 ar
= AnalysisResultPtr(new AnalysisResult());
333 ar
->loadBuiltinFunctions();
334 string slib
= get_systemlib();
336 Scanner
scanner(slib
.c_str(), slib
.size(),
337 Option::GetScannerType(), "systemlib.php");
338 Compiler::Parser
parser(scanner
, "systemlib.php", ar
);
339 if (!parser
.parse()) {
340 Logger::Error("Unable to parse systemlib.php: %s",
341 parser
.getMessage().c_str());
345 ar
->analyzeProgram(true);
347 const StringToFileScopePtrMap
&files
= ar
->getAllFiles();
348 for (StringToFileScopePtrMap::const_iterator iterFile
= files
.begin();
349 iterFile
!= files
.end(); iterFile
++) {
350 const StringToClassScopePtrVecMap
&classes
=
351 iterFile
->second
->getClasses();
352 for (StringToClassScopePtrVecMap::const_iterator iter
= classes
.begin();
353 iter
!= classes
.end(); ++iter
) {
354 assert(iter
->second
.size() == 1);
355 iter
->second
[0]->setSystem();
356 assert(!s_classes
[iter
->first
]);
357 s_classes
[iter
->first
] = iter
->second
[0];
361 NoSuperGlobals
= true;
364 // load extension constants, classes and dynamics
365 ImportExtConstants(ar
, s_constants
, ClassInfo::GetSystem());
366 ImportExtClasses(ar
);
369 Array constants
= ClassInfo::GetSystemConstants();
370 LocationPtr
loc(new Location
);
371 for (ArrayIter it
= constants
.begin(); it
; ++it
) {
372 CVarRef key
= it
.first();
373 if (!key
.isString()) continue;
374 std::string name
= key
.toCStrRef().data();
375 if (s_constants
->getSymbol(name
)) continue;
376 if (name
== "true" || name
== "false" || name
== "null") continue;
377 CVarRef value
= it
.secondRef();
378 if (!value
.isInitialized() || value
.isObject()) continue;
379 ExpressionPtr e
= Expression::MakeScalarExpression(ar2
, ar2
, loc
, value
);
381 value
.isNull() ? Type::Null
:
382 value
.isBoolean() ? Type::Boolean
:
383 value
.isInteger() ? Type::Int64
:
384 value
.isDouble() ? Type::Double
:
385 value
.isArray() ? Type::Array
: Type::Variant
;
387 s_constants
->add(key
.toCStrRef().data(), t
, e
, ar2
, e
);
389 s_variables
= ar2
->getVariables();
390 for (int i
= 0, n
= NumGlobalNames(); i
< n
; ++i
) {
391 s_variables
->add(GlobalNames
[i
], Type::Variant
, false, ar
,
392 ConstructPtr(), ModifierExpressionPtr());
395 s_constants
->setDynamic(ar
, "SID", true);
400 AnalysisResultPtr
BuiltinSymbols::LoadGlobalSymbols(const char *fileName
) {
401 AnalysisResultPtr
ar(new AnalysisResult());
402 string phpBaseName
= "/system/globals/";
403 phpBaseName
+= fileName
;
404 string phpFileName
= Option::GetSystemRoot() + phpBaseName
;
405 const char *baseName
= s_strings
.add(phpBaseName
.c_str());
406 fileName
= s_strings
.add(phpFileName
.c_str());
409 Scanner
scanner(fileName
, Option::GetScannerType());
410 Compiler::Parser
parser(scanner
, baseName
, ar
);
411 if (!parser
.parse()) {
413 Logger::Error("Unable to parse file %s: %s", fileName
,
414 parser
.getMessage().c_str());
416 } catch (FileOpenException
&e
) {
417 Logger::Error("%s", e
.getMessage().c_str());
419 ar
->analyzeProgram(true);
424 void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar
,
425 StringToFunctionScopePtrMap
&functions
) {
427 functions
.insert(s_functions
.begin(), s_functions
.end());
430 void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar
,
431 StringToClassScopePtrMap
&classes
) {
433 classes
.insert(s_classes
.begin(), s_classes
.end());
436 void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar
,
437 VariableTablePtr variables
) {
440 variables
->import(s_variables
);
444 void BuiltinSymbols::LoadConstants(AnalysisResultPtr ar
,
445 ConstantTablePtr constants
) {
448 constants
->import(s_constants
);
452 ConstantTablePtr
BuiltinSymbols::LoadSystemConstants() {
453 AnalysisResultPtr ar
= LoadGlobalSymbols("constants.php");
454 const auto &fileScopes
= ar
->getAllFilesVector();
455 if (!fileScopes
.empty()) {
456 return fileScopes
[0]->getConstants();
458 throw std::runtime_error("LoadSystemConstants failed");
461 void BuiltinSymbols::LoadSuperGlobals() {
462 if (s_superGlobals
.empty()) {
463 s_superGlobals
["_SERVER"] = Type::Variant
;
464 s_superGlobals
["_GET"] = Type::Variant
;
465 s_superGlobals
["_POST"] = Type::Variant
;
466 s_superGlobals
["_COOKIE"] = Type::Variant
;
467 s_superGlobals
["_FILES"] = Type::Variant
;
468 s_superGlobals
["_ENV"] = Type::Variant
;
469 s_superGlobals
["_REQUEST"] = Type::Variant
;
470 s_superGlobals
["_SESSION"] = Type::Variant
;
471 s_superGlobals
["http_response_header"] = Type::Variant
;
475 bool BuiltinSymbols::IsSuperGlobal(const std::string
&name
) {
476 if (NoSuperGlobals
) return false;
477 return s_superGlobals
.find(name
) != s_superGlobals
.end();
480 TypePtr
BuiltinSymbols::GetSuperGlobalType(const std::string
&name
) {
481 StringToTypePtrMap::const_iterator iter
= s_superGlobals
.find(name
);
482 if (iter
!= s_superGlobals
.end()) {