rename IgnoreRedefinition to AllowOverride
[hiphop-php.git] / hphp / compiler / builtin_symbols.cpp
blobcee047bd681dafb2eae470cdbd806352ec8ee220
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
38 #include <dlfcn.h>
40 using namespace HPHP;
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[] = {
58 "HTTP_RAW_POST_DATA",
59 "_COOKIE",
60 "_ENV",
61 "_FILES",
62 "_GET",
63 "_POST",
64 "_REQUEST",
65 "_SERVER",
66 "_SESSION",
67 "argc",
68 "argv",
69 "http_response_header",
72 const char *BuiltinSymbols::SystemClasses[] = {
73 "stdclass",
74 "exception",
75 "arrayaccess",
76 "iterator",
77 "collections",
78 "reflection",
79 "splobjectstorage",
80 "directory",
81 "splfile",
82 "debugger",
83 "xhprof",
84 "directoryiterator",
85 "soapfault",
86 "fbmysqllexer",
87 nullptr
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) {
104 switch (dt) {
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;
112 case KindOfUnknown:
113 default:
114 return unknown;
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,
123 method->name.data(),
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]) {
131 ++reqCount;
133 ++totalCount;
135 f->setParamCounts(ar, reqCount, totalCount);
137 int idx = 0;
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) {
143 f->setRefParam(idx);
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,
154 Type::Variant));
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);
175 if (isMethod) {
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) {
195 f->setNoEffect();
197 if (attrs & ClassInfo::FunctionIsFoldable) {
198 f->setIsFoldable();
200 if (attrs & ClassInfo::ContextSensitive) {
201 f->setContextSensitive(true);
203 if (attrs & ClassInfo::NeedsActRec) {
204 f->setNeedsActRec();
206 if ((attrs & ClassInfo::AllowOverride) && !isMethod) {
207 f->setAllowOverride();
210 FunctionScope::RecordFunctionInfo(f->getName(), f);
211 return f;
214 void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
215 StringToFunctionScopePtrMap &map,
216 ClassInfo *cls) {
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,
227 ClassInfo *cls) {
228 const ClassInfo::MethodVec &methods = cls->getMethodsVec();
229 for (auto it = methods.begin(); it != methods.end(); ++it) {
230 FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
231 vec.push_back(f);
235 void BuiltinSymbols::ImportExtProperties(AnalysisResultPtr ar,
236 VariableTablePtr dest,
237 ClassInfo *cls) {
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,
261 ClassInfo *cls) {
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,
277 ClassInfo *cls) {
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());
304 cl->setSystem();
305 return cl;
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;
319 Loaded = true;
321 if (g_context.isNull()) init_thread_locals();
322 ClassInfo::Load();
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
331 if (!extOnly) {
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());
342 assert(false);
345 ar->analyzeProgram(true);
346 ar->inferTypes();
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];
360 } else {
361 NoSuperGlobals = true;
364 // load extension constants, classes and dynamics
365 ImportExtConstants(ar, s_constants, ClassInfo::GetSystem());
366 ImportExtClasses(ar);
368 if (!extOnly) {
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);
380 TypePtr t =
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);
397 return 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());
408 try {
409 Scanner scanner(fileName, Option::GetScannerType());
410 Compiler::Parser parser(scanner, baseName, ar);
411 if (!parser.parse()) {
412 assert(false);
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);
420 ar->inferTypes();
421 return ar;
424 void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
425 StringToFunctionScopePtrMap &functions) {
426 assert(Loaded);
427 functions.insert(s_functions.begin(), s_functions.end());
430 void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
431 StringToClassScopePtrMap &classes) {
432 assert(Loaded);
433 classes.insert(s_classes.begin(), s_classes.end());
436 void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar,
437 VariableTablePtr variables) {
438 assert(Loaded);
439 if (s_variables) {
440 variables->import(s_variables);
444 void BuiltinSymbols::LoadConstants(AnalysisResultPtr ar,
445 ConstantTablePtr constants) {
446 assert(Loaded);
447 if (s_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()) {
483 return iter->second;
485 return TypePtr();