Arquivos
Jordan DeLong 040e87ba69 Make type hint errors disallow recovery if repo was compiled with HardTypeHints
Fix a long-standing issue that could segfault the VM in
RepoAuthoritative mode (not in practice in www, since our error
handler always throws in this case).  To do this, adds a Repo global
metadata blob that we can use to communicate whatever global
compilation information we want to the runtime (I've wished we had
this for a few things in the past).

Reviewed By: @edwinsmith

Differential Revision: D1125218
2014-01-17 01:43:42 -08:00

393 linhas
13 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/parser/scanner.h"
#include "hphp/util/logger.h"
#include "hphp/util/db-query.h"
#include "hphp/util/util.h"
#include "hphp/util/process.h"
#include "hphp/hhbbc/hhbbc.h"
#include <boost/algorithm/string/trim.hpp>
#include "hphp/runtime/base/preg.h"
namespace HPHP {
using std::set;
using std::map;
using std::map;
///////////////////////////////////////////////////////////////////////////////
std::string Option::RootDirectory;
set<string> Option::PackageDirectories;
set<string> Option::PackageFiles;
set<string> Option::PackageExcludeDirs;
set<string> Option::PackageExcludeFiles;
set<string> Option::PackageExcludePatterns;
set<string> Option::PackageExcludeStaticDirs;
set<string> Option::PackageExcludeStaticFiles;
set<string> Option::PackageExcludeStaticPatterns;
bool Option::CachePHPFile = false;
vector<string> Option::ParseOnDemandDirs;
map<string, string> Option::IncludeRoots;
map<string, string> Option::AutoloadRoots;
vector<string> Option::IncludeSearchPaths;
string Option::DefaultIncludeRoot;
map<string, int> Option::DynamicFunctionCalls;
bool Option::GeneratePickledPHP = false;
bool Option::GenerateInlinedPHP = false;
bool Option::GenerateTrimmedPHP = false;
bool Option::GenerateInferredTypes = false;
bool Option::ConvertSuperGlobals = false;
bool Option::ConvertQOpExpressions = false;
string Option::ProgramPrologue;
string Option::TrimmedPrologue;
vector<string> Option::DynamicFunctionPrefixes;
vector<string> Option::DynamicFunctionPostfixes;
vector<string> Option::DynamicMethodPrefixes;
vector<string> Option::DynamicMethodPostfixes;
vector<string> Option::DynamicClassPrefixes;
vector<string> Option::DynamicClassPostfixes;
set<string> Option::DynamicInvokeFunctions;
set<string> Option::VolatileClasses;
map<string,string> Option::AutoloadClassMap;
map<string,string> Option::AutoloadFuncMap;
map<string,string> Option::AutoloadConstMap;
string Option::AutoloadRoot;
map<string, string> Option::FunctionSections;
bool Option::GenerateTextHHBC = false;
bool Option::GenerateBinaryHHBC = false;
string Option::RepoCentralPath;
bool Option::RepoDebugInfo = false;
string Option::IdPrefix = "$$";
string Option::LabelEscape = "$";
string Option::LambdaPrefix = "df_";
string Option::Tab = " ";
const char *Option::UserFilePrefix = "php/";
const char *Option::ClassHeaderPrefix = "cls/";
bool Option::PreOptimization = false;
bool Option::PostOptimization = false;
bool Option::SeparateCompilation = false;
bool Option::SeparateCompLib = false;
bool Option::AnalyzePerfectVirtuals = true;
bool Option::HardTypeHints = true;
bool Option::KeepStatementsWithNoEffect = false;
int Option::ConditionalIncludeExpandLevel = 1;
int Option::DependencyMaxProgram = 1;
int Option::CodeErrorMaxProgram = 1;
Option::EvalLevel Option::EnableEval = NoEval;
std::string Option::ProgramName;
bool Option::ParseTimeOpts = true;
bool Option::EnableHipHopSyntax = false;
bool Option::EnableZendCompat = false;
bool Option::JitEnableRenameFunction = false;
bool Option::EnableHipHopExperimentalSyntax = false;
bool Option::EnableShortTags = true;
bool Option::EnableAspTags = false;
bool Option::EnableXHP = false;
int Option::ParserThreadCount = 0;
int Option::GetScannerType() {
int type = 0;
if (EnableShortTags) type |= Scanner::AllowShortTags;
if (EnableAspTags) type |= Scanner::AllowAspTags;
if (EnableXHP) type |= Scanner::AllowXHPSyntax;
if (EnableHipHopSyntax) type |= Scanner::AllowHipHopSyntax;
return type;
}
int Option::InvokeFewArgsCount = 6;
int Option::InlineFunctionThreshold = -1;
bool Option::EliminateDeadCode = true;
bool Option::CopyProp = false;
bool Option::LocalCopyProp = true;
bool Option::StringLoopOpts = true;
int Option::AutoInline = 0;
bool Option::ControlFlow = true;
bool Option::VariableCoalescing = false;
bool Option::ArrayAccessIdempotent = false;
bool Option::DumpAst = false;
bool Option::WholeProgram = true;
bool Option::UseHHBBC = getenv("HHVM_HHBBC");
bool Option::RecordErrors = true;
std::string Option::DocJson;
bool Option::AllDynamic = true;
bool Option::AllVolatile = false;
StringBag Option::OptionStrings;
bool Option::GenerateDocComments = true;
void (*Option::m_hookHandler)(Hdf &config);
bool (*Option::PersistenceHook)(BlockScopeRawPtr scope, FileScopeRawPtr file);
///////////////////////////////////////////////////////////////////////////////
// load from HDF file
void Option::LoadRootHdf(const Hdf &roots, map<string, string> &map) {
if (roots.exists()) {
for (Hdf hdf = roots.firstChild(); hdf.exists(); hdf = hdf.next()) {
map[hdf["root"].get()] = hdf["path"].get();
}
}
}
void Option::LoadRootHdf(const Hdf &roots, vector<string> &vec) {
if (roots.exists()) {
for (Hdf hdf = roots.firstChild(); hdf.exists(); hdf = hdf.next()) {
vec.push_back(hdf.getString(""));
}
}
}
void Option::Load(Hdf &config) {
LoadRootHdf(config["IncludeRoots"], IncludeRoots);
LoadRootHdf(config["AutoloadRoots"], AutoloadRoots);
config["PackageFiles"].get(PackageFiles);
config["IncludeSearchPaths"].get(IncludeSearchPaths);
config["PackageDirectories"].get(PackageDirectories);
config["PackageExcludeDirs"].get(PackageExcludeDirs);
config["PackageExcludeFiles"].get(PackageExcludeFiles);
config["PackageExcludePatterns"].get(PackageExcludePatterns);
config["PackageExcludeStaticDirs"].get(PackageExcludeStaticDirs);
config["PackageExcludeStaticFiles"].get(PackageExcludeStaticFiles);
config["PackageExcludeStaticPatterns"].get(PackageExcludeStaticPatterns);
CachePHPFile = config["CachePHPFile"].getBool();
config["ParseOnDemandDirs"].get(ParseOnDemandDirs);
{
Hdf cg = config["CodeGeneration"];
string tmp;
#define READ_CG_OPTION(name) \
tmp = cg[#name].getString(); \
if (!tmp.empty()) { \
name = OptionStrings.add(tmp.c_str()); \
}
READ_CG_OPTION(IdPrefix);
READ_CG_OPTION(LabelEscape);
READ_CG_OPTION(LambdaPrefix);
}
config["DynamicFunctionPrefix"].get(DynamicFunctionPrefixes);
config["DynamicFunctionPostfix"].get(DynamicFunctionPostfixes);
config["DynamicMethodPrefix"].get(DynamicMethodPrefixes);
config["DynamicInvokeFunctions"].get(DynamicInvokeFunctions);
config["VolatileClasses"].get(VolatileClasses);
// build map from function names to sections
for (Hdf hdf = config["FunctionSections"].firstChild(); hdf.exists();
hdf = hdf.next()) {
for (Hdf hdfFunc = hdf.firstChild(); hdfFunc.exists();
hdfFunc = hdfFunc.next()) {
FunctionSections[hdfFunc.getString()] = hdf.getName();
}
}
{
Hdf repo = config["Repo"];
{
Hdf repoCentral = repo["Central"];
RepoCentralPath = repoCentral["Path"].getString();
}
RepoDebugInfo = repo["DebugInfo"].getBool(false);
}
{
Hdf autoloadMap = config["AutoloadMap"];
autoloadMap["class"].get(AutoloadClassMap);
autoloadMap["function"].get(AutoloadFuncMap);
autoloadMap["constant"].get(AutoloadConstMap);
AutoloadRoot = autoloadMap["root"].getString();
}
HardTypeHints = config["HardTypeHints"].getBool(true);
EnableHipHopSyntax = config["EnableHipHopSyntax"].getBool();
EnableZendCompat = config["EnableZendCompat"].getBool();
JitEnableRenameFunction = config["JitEnableRenameFunction"].getBool();
EnableHipHopExperimentalSyntax =
config["EnableHipHopExperimentalSyntax"].getBool();
EnableShortTags = config["EnableShortTags"].getBool(true);
EnableAspTags = config["EnableAspTags"].getBool();
EnableXHP = config["EnableXHP"].getBool(false);
if (EnableHipHopSyntax) {
// If EnableHipHopSyntax is true, it forces EnableXHP to true
// regardless of how it was set in the config
EnableXHP = true;
}
ParserThreadCount = config["ParserThreadCount"].getInt32(0);
if (ParserThreadCount <= 0) {
ParserThreadCount = Process::GetCPUCount();
}
EnableEval = (EvalLevel)config["EnableEval"].getByte(0);
AllDynamic = config["AllDynamic"].getBool(true);
AllVolatile = config["AllVolatile"].getBool();
GenerateDocComments = config["GenerateDocComments"].getBool(true);
EliminateDeadCode = config["EliminateDeadCode"].getBool(true);
CopyProp = config["CopyProp"].getBool(false);
LocalCopyProp = config["LocalCopyProp"].getBool(true);
StringLoopOpts = config["StringLoopOpts"].getBool(true);
AutoInline = config["AutoInline"].getInt32(0);
ControlFlow = config["ControlFlow"].getBool(true);
VariableCoalescing = config["VariableCoalescing"].getBool(false);
ArrayAccessIdempotent = config["ArrayAccessIdempotent"].getBool(false);
DumpAst = config["DumpAst"].getBool(false);
WholeProgram = config["WholeProgram"].getBool(true);
UseHHBBC = config["UseHHBBC"].getBool(UseHHBBC);
// Temporary, during file-cache migration.
FileCache::UseNewCache = config["UseNewCache"].getBool(false);
if (m_hookHandler) m_hookHandler(config);
OnLoad();
}
void Option::Load() {
OnLoad();
}
void Option::OnLoad() {
// all lambda functions are dynamic automatically
DynamicFunctionPrefixes.push_back(LambdaPrefix);
}
///////////////////////////////////////////////////////////////////////////////
bool Option::IsDynamicFunction(bool method, const std::string &name) {
if (method) {
return IsDynamic(name, DynamicMethodPrefixes, DynamicMethodPostfixes);
}
return IsDynamic(name, DynamicFunctionPrefixes, DynamicFunctionPostfixes);
}
bool Option::IsDynamicClass(const std::string &name) {
return IsDynamic(name, DynamicClassPrefixes, DynamicClassPostfixes);
}
bool Option::IsDynamic(const std::string &name,
const std::vector<std::string> &prefixes,
const std::vector<std::string> &postfixes) {
if (name.substr(0, 4) == "dyn_") return true;
for (unsigned int i = 0; i < prefixes.size(); i++) {
const string &prefix = prefixes[i];
if (name.substr(0, prefix.length()) == prefix) {
return true;
}
}
for (unsigned int i = 0; i < postfixes.size(); i++) {
const string &postfix = postfixes[i];
if (name.length() > postfix.length() &&
name.substr(name.length() - postfix.length()) == postfix) {
return true;
}
}
return false;
}
std::string Option::GetAutoloadRoot(const std::string &name) {
for (map<string, string>::const_iterator iter = AutoloadRoots.begin();
iter != AutoloadRoots.end(); ++iter) {
if (name.substr(0, iter->first.length()) == iter->first) {
return iter->second;
}
}
return "";
}
std::string Option::MangleFilename(const std::string &name, bool id) {
string ret = UserFilePrefix;
ret += name;
if (id) {
Util::replaceAll(ret, "/", "$");
Util::replaceAll(ret, "-", "_");
Util::replaceAll(ret, ".", "_");
}
return ret;
}
bool Option::IsFileExcluded(const std::string &file,
const std::set<std::string> &patterns) {
String sfile(file.c_str(), file.size(), CopyString);
for (set<string>::const_iterator iter = patterns.begin();
iter != patterns.end(); ++iter) {
const std::string &pattern = *iter;
Variant matches;
Variant ret = preg_match(String(pattern.c_str(), pattern.size(),
CopyString), sfile, matches);
if (ret.toInt64() > 0) {
return true;
}
}
return false;
}
void Option::FilterFiles(std::vector<std::string> &files,
const std::set<std::string> &patterns) {
for (int i = files.size() - 1; i >= 0; i--) {
if (IsFileExcluded(files[i], patterns)) {
files.erase(files.begin() + i);
}
}
}
//////////////////////////////////////////////////////////////////////
void initialize_hhbbc_options() {
if (!Option::UseHHBBC) return;
HHBBC::options.InterceptableFunctions = Option::DynamicInvokeFunctions;
HHBBC::options.HardTypeHints = Option::HardTypeHints;
}
//////////////////////////////////////////////////////////////////////
}