Arquivos
hhvm/hphp/compiler/analysis/constant_table.cpp
T
mwilliams 4eaf40d7aa Generate g_class_map directly from the idl
This is the last step to being able to get rid of the c++ code
gen in hphp. "make -Chphp/system" is now a no-op.

I'll rip out the actual c++ generating code as a separate diff.
2013-03-08 17:52:31 -08:00

466 linhas
16 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/constant_table.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/type.h>
#include <compiler/code_generator.h>
#include <compiler/expression/expression.h>
#include <compiler/expression/scalar_expression.h>
#include <compiler/option.h>
#include <util/util.h>
#include <util/hash.h>
#include <compiler/analysis/class_scope.h>
#include <runtime/base/complex_types.h>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
ConstantTable::ConstantTable(BlockScope &blockScope)
: SymbolTable(blockScope, true),
m_hasDynamic(false) {
}
///////////////////////////////////////////////////////////////////////////////
TypePtr ConstantTable::add(const std::string &name, TypePtr type,
ExpressionPtr exp, AnalysisResultConstPtr ar,
ConstructPtr construct) {
if (name == "true" || name == "false") {
return Type::Boolean;
}
Symbol *sym = genSymbol(name, true);
if (!sym->declarationSet()) {
assert(!sym->valueSet());
setType(ar, sym, type, true);
sym->setDeclaration(construct);
sym->setValue(exp);
return type;
}
assert(sym->declarationSet() && sym->valueSet());
if (m_blockScope.isFirstPass()) {
if (construct) {
if (exp != sym->getValue()) {
Compiler::Error(Compiler::DeclaredConstantTwice, construct,
sym->getDeclaration());
if (!sym->isDynamic()) {
sym->setDynamic();
m_hasDynamic = true;
}
type = Type::Variant;
}
} else if (exp) {
sym->setValue(exp);
}
setType(ar, sym, type, true);
}
return type;
}
void ConstantTable::setDynamic(AnalysisResultConstPtr ar,
const std::string &name, bool forceVariant) {
Symbol *sym = genSymbol(name, true);
if (!sym->isDynamic()) {
Lock lock(BlockScope::s_constMutex);
sym->setDynamic();
if (sym->getDeclaration()) {
sym->getDeclaration()->getScope()->
addUpdates(BlockScope::UseKindConstRef);
}
m_hasDynamic = true;
if (forceVariant) {
setType(ar, sym, Type::Variant, true);
}
}
}
void ConstantTable::setValue(AnalysisResultConstPtr ar, const std::string &name,
ExpressionPtr value) {
Symbol *sym = getSymbol(name);
assert(sym && sym->isPresent());
sym->setValue(value);
}
bool ConstantTable::isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const {
if (const Symbol *sym ATTRIBUTE_UNUSED = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
return true;
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
return parent->getConstants()->isRecursivelyDeclared(ar, name);
}
return false;
}
ConstructPtr ConstantTable::getValueRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass) const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getValue()) return sym->getValue();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getValueRecur(ar, name, defClass);
}
return ConstructPtr();
}
ConstructPtr ConstantTable::getDeclarationRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass)
const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getDeclaration()) return sym->getDeclaration();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getDeclarationRecur(ar, name, defClass);
}
return ConstructPtr();
}
void ConstantTable::cleanupForError(AnalysisResultConstPtr ar) {
AnalysisResult::Locker lock(ar);
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (!sym->isDynamic()) {
sym->setDynamic();
sym->setDeclaration(ConstructPtr());
sym->setValue(ConstructPtr());
}
}
}
TypePtr ConstantTable::check(BlockScopeRawPtr context,
const std::string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope) {
assert(!m_blockScope.is(BlockScope::FunctionScope));
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
TypePtr actualType;
defScope = nullptr;
if (name == "true" || name == "false") {
actualType = Type::Boolean;
} else {
Symbol *sym = getSymbol(name);
if (!sym) {
if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (isClassScope) {
ClassScopeRawPtr parent = findBase(ar, name, bases);
if (parent) {
actualType = parent->getConstants()->check(
context, name, type, coerce, ar, construct, bases, defScope);
if (defScope) return actualType;
}
}
if (!isClassScope || !((ClassScope*)&m_blockScope)->isTrait()) {
Compiler::Error(Compiler::UseUndeclaredConstant, construct);
}
actualType = isClassScope || !Option::WholeProgram ?
Type::Variant : Type::String;
}
} else {
assert(sym->isPresent());
assert(sym->getType());
assert(sym->isConstant());
defScope = &m_blockScope;
if (isClassScope) {
// if the current scope is a function scope, grab the lock.
// otherwise if it's a class scope, then *try* to grab the lock.
if (context->is(BlockScope::FunctionScope)) {
GET_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
} else {
TRY_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
}
} else {
Lock lock(m_blockScope.getMutex());
return setType(ar, sym, type, coerce);
}
}
}
return actualType;
}
ClassScopePtr ConstantTable::findParent(AnalysisResultConstPtr ar,
const std::string &name) const {
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
parent && !parent->isRedeclaring();
parent = parent->getParentScope(ar)) {
if (parent->hasConst(name)) {
return parent;
}
}
return ClassScopePtr();
}
ClassScopeRawPtr ConstantTable::findBase(
AnalysisResultConstPtr ar, const std::string &name,
const std::vector<std::string> &bases) const {
for (int i = bases.size(); i--; ) {
ClassScopeRawPtr p = ar->findClass(bases[i]);
if (!p || p->isRedeclaring()) continue;
if (p->hasConst(name)) return p;
ConstantTablePtr constants = p->getConstants();
p = constants->findBase(ar, name, p->getBases());
if (p) return p;
}
return ClassScopeRawPtr();
}
///////////////////////////////////////////////////////////////////////////////
void ConstantTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (Option::GenerateInferredTypes) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (sym->isSystem()) continue;
cg_printf("// @const %s\t$%s\n",
sym->getFinalType()->toString().c_str(),
sym->getName().c_str());
}
}
}
void ConstantTable::getCPPDynamicDecl(CodeGenerator &cg,
AnalysisResultPtr ar,
Type2SymbolSetMap &type2names) {
const char *prefix = Option::ConstantPrefix;
string classId;
const char *fmt = "";
ClassScopePtr scope = getClassScope();
if (scope) {
prefix = Option::ClassConstantPrefix;
classId = scope->getId();
fmt = Option::IdPrefix.c_str();
}
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
SymbolSet &symbols = type2names["Variant"];
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic() &&
system == sym->isSystem()) {
string tmp = string(prefix) + classId + fmt +
CodeGenerator::FormatLabel(sym->getName());
if (Type::IsMappedToVariant(sym->getFinalType())) {
symbols.insert(tmp);
} else {
type2names[sym->getFinalType()->getCPPDecl(ar, BlockScopeRawPtr())].
insert(tmp);
}
}
}
}
void ConstantTable::outputCPPDynamicImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic()) {
cg_printf("%s%s = \"%s\";\n", Option::ConstantPrefix,
CodeGenerator::FormatLabel(sym->getName()).c_str(),
CodeGenerator::EscapeLabel(sym->getName()).c_str());
}
}
}
void ConstantTable::collectCPPGlobalSymbols(StringPairSet &symbols,
CodeGenerator &cg,
AnalysisResultPtr ar) {
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic()) {
string varname = Option::ConstantPrefix +
CodeGenerator::FormatLabel(sym->getName());
symbols.insert(StringPair(varname, varname));
}
}
}
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
bool newline /* = true */) const {
bool printed = false;
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (outputCPP(cg, ar, sym)) printed = true;
}
if (newline && printed) {
cg_printf("\n");
}
}
bool ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
const Symbol *sym) const {
bool decl = true;
if (cg.getContext() == CodeGenerator::CppConstantsDecl) {
decl = false;
}
if (!const_cast<Symbol*>(sym)->checkDefined() ||
sym->isDynamic()) {
return false;
}
if (sym->isSystem() && cg.getOutput() != CodeGenerator::SystemCPP) {
return false;
}
const string &name = sym->getName();
ConstructPtr value = sym->getValue();
cg_printf(decl ? "extern const " : "const ");
TypePtr type = sym->getFinalType();
bool isString = type->is(Type::KindOfString);
if (isString) {
cg_printf("StaticString");
} else {
type->outputCPPDecl(cg, ar, getBlockScope());
}
ClassScope *cls = dynamic_cast<ClassScope*>(&m_blockScope);
if (decl) {
if (!cls) {
cg_printf(" %s%s", Option::ConstantPrefix,
CodeGenerator::FormatLabel(name).c_str());
} else {
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
cls->getId().c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(name).c_str());
}
} else {
if (!cls) {
cg_printf(" %s%s", Option::ConstantPrefix,
CodeGenerator::FormatLabel(name).c_str());
} else {
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
cls->getId().c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(name).c_str());
}
cg_printf(isString ? "(" : " = ");
if (value) {
ExpressionPtr exp = dynamic_pointer_cast<Expression>(value);
if (isString && exp->isScalar()) {
ScalarExpressionPtr scalarExp =
dynamic_pointer_cast<ScalarExpression>(exp);
if (scalarExp) {
cg_printf("LITSTR_INIT(%s)",
scalarExp->getCPPLiteralString().c_str());
} else {
Variant v;
exp->getScalarValue(v);
cg_printf("LITSTR_INIT(\"%s\")",
CodeGenerator::EscapeLabel(v.toString().data()).c_str());
}
} else {
exp->outputCPP(cg, ar);
}
} else {
cg_printf("\"%s\"", CodeGenerator::EscapeLabel(name).c_str());
}
if (isString) {
cg_printf(")");
}
}
cg_printf(";\n");
return true;
}
bool ConstantTable::outputSingleConstant(CodeGenerator &cg,
AnalysisResultPtr ar,
const std::string &name) const {
const Symbol *sym = getSymbol(name);
return sym && outputCPP(cg, ar, sym);
}
void ConstantTable::outputCPPConstantSymbol(CodeGenerator &cg,
AnalysisResultPtr ar,
Symbol *sym) {
ClassScopeRawPtr cls = getClassScope();
if (true/* sym->valueSet() &&
(cls || (!sym->isDynamic() &&
!ar->isConstantRedeclared(sym->getName()))) */) {
ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue());
Variant v;
cg_printf("\"%s\", ", CodeGenerator::EscapeLabel(sym->getName()).c_str());
if (value && value->getScalarValue(v)) {
int len;
string output = getEscapedText(v, len);
cg_printf("(const char *)%d, \"%s\",\n",
len, output.c_str());
} else if (cls) {
DataType dt = sym->getFinalType()->getDataType();
always_assert(dt >= -1 && dt < 255);
cg_printf("(const char *)&%s%s%s%s, (const char*)0x%x,\n",
Option::ClassConstantPrefix, cls->getId().c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(sym->getName()).c_str(),
(int)dt + 2);
} else {
DataType dt = sym->getFinalType()->getDataType();
if (sym->isDynamic()) {
always_assert(dt == KindOfUnknown);
cg_printf("(const char *)"
"((offsetof(SystemGlobals, %s%s) -"
" offsetof(SystemGlobals, stgv_Variant)) / "
"sizeof(Variant)), "
"(const char *)%d,\n",
Option::ConstantPrefix,
CodeGenerator::FormatLabel(sym->getName()).c_str(),
(int)dt + 2);
} else if (dt == KindOfObject) {
if (sym->getName() == "STDERR") {
cg_printf("(const char *)&BuiltinFiles::GetSTDERR, nullptr,\n");
} else if (sym->getName() == "STDIN") {
cg_printf("(const char *)&BuiltinFiles::GetSTDIN, nullptr,\n");
} else if (sym->getName() == "STDOUT") {
cg_printf("(const char *)&BuiltinFiles::GetSTDOUT, nullptr,\n");
} else {
not_reached();
}
} else {
always_assert(dt != KindOfUnknown);
cg_printf("(const char *)&%s%s, (const char*)0x%x,\n",
Option::ConstantPrefix,
CodeGenerator::FormatLabel(sym->getName()).c_str(),
(int)dt + 2);
}
}
}
}
void ConstantTable::outputCPPClassMap(CodeGenerator &cg,
AnalysisResultPtr ar,
bool last /* = true */) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
outputCPPConstantSymbol(cg, ar, m_symbolVec[i]);
}
if (last) cg_printf("NULL,\n");
}