49269952c8
This is to clear the runway for getting rid of GlobalNameValueTableWrapper. It moves aside these three items that were in there for no particular reason other than convenience. I moved them aside into another struct that I arena-allocate and initialize at the same time as the global VarEnv (which initializes the GlobalNVTW). I called the struct where these live "EnvConstants" since they look like constants to PHP but their values are determined at startup time (by the environment, like whether we're in server mode). lvalProxy doesn't fit that mold, but oh well.
400 linhas
12 KiB
C++
400 linhas
12 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 <algorithm>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
|
|
#include "folly/FBString.h"
|
|
#include "folly/FBVector.h"
|
|
|
|
#include "hphp/tools/bootstrap/idl.h"
|
|
|
|
using folly::fbstring;
|
|
using folly::fbvector;
|
|
using namespace HPHP::IDL;
|
|
using namespace HPHP;
|
|
|
|
#define VISIBILITY_MASK (IsPublic|IsProtected|IsPrivate)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Helpers
|
|
|
|
static inline fbstring castLong(unsigned long lval, bool hex = false) {
|
|
if (hex) {
|
|
char buffer[10];
|
|
snprintf(buffer, sizeof(buffer), "%lx", lval & 0xffffffff);
|
|
return folly::to<fbstring>("(const char *)0x", buffer);
|
|
}
|
|
return folly::to<fbstring>("(const char*)", lval);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Generated doc comments
|
|
|
|
static fbstring formatDocComment(const fbstring& comment) {
|
|
const char *p = comment.c_str();
|
|
const char *s;
|
|
const char *e = p + comment.size();
|
|
fbstring ret("/**\n");
|
|
while ((s = strchr(p, '\n'))) {
|
|
ret += " *";
|
|
if ((s - p) > 1) {
|
|
ret += " " + fbstring(p, (s - p));
|
|
}
|
|
ret += "\n";
|
|
p = s + 1;
|
|
}
|
|
if (p < e) {
|
|
ret += " * " + fbstring(p) + "\n";
|
|
}
|
|
return ret + " */";
|
|
}
|
|
|
|
static fbstring genDocCommentPreamble(const fbstring& name,
|
|
const fbstring& desc,
|
|
long flags,
|
|
const fbstring& classname) {
|
|
fbstring ret;
|
|
|
|
if (flags & HipHopSpecific) {
|
|
ret = "( HipHop specific )";
|
|
} else {
|
|
ret = "( excerpt from http://php.net/manual/en/";
|
|
if (classname.size()) {
|
|
ret += classname + ".";
|
|
} else {
|
|
ret += "function.";
|
|
}
|
|
ret += name + ".php )";
|
|
}
|
|
|
|
if (desc.size()) {
|
|
ret += "\n" + desc;
|
|
}
|
|
return ret + "\n\n";
|
|
}
|
|
|
|
static fbstring genDocComment(const PhpFunc& func,
|
|
const fbstring& classname) {
|
|
fbstring ret(genDocCommentPreamble(func.name(), func.getDesc(),
|
|
func.flags(), classname));
|
|
|
|
for (auto ¶m : func.params()) {
|
|
ret += "@" + param.name() + " " + param.getPhpType() + " ";
|
|
if (param.isRef()) {
|
|
ret += "(output) ";
|
|
}
|
|
ret += param.getDesc() + "\n";
|
|
}
|
|
|
|
if (func.numParams() > 0) {
|
|
ret += "\n";
|
|
}
|
|
|
|
auto rko = func.returnKindOf();
|
|
if ((rko != KindOfNull) && (rko != KindOfInvalid)) {
|
|
ret += "@return " + func.returnPhpType() + " ";
|
|
if (func.isReturnRef()) {
|
|
ret += "(output) ";
|
|
}
|
|
ret += func.returnDesc() + "\n";
|
|
}
|
|
|
|
return formatDocComment(ret);
|
|
}
|
|
|
|
static fbstring genDocComment(const PhpClass& cls) {
|
|
return formatDocComment(
|
|
genDocCommentPreamble(cls.name(), cls.getDesc(), cls.flags(), "")
|
|
);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// System constants
|
|
|
|
static void declareConstants(std::ostream &out,
|
|
const fbvector<PhpConst>& consts,
|
|
bool extrn) {
|
|
for (auto c : consts) {
|
|
if (!c.hasValue()) {
|
|
continue;
|
|
}
|
|
|
|
if (extrn) {
|
|
out << "extern const " << c.getCppType() << " " << c.varname() << ";\n";
|
|
} else if (c.kindOf() == KindOfString) {
|
|
fbstring val = c.value();
|
|
out << "extern const StaticString " << c.varname()
|
|
<< "(\"" << escapeCpp(val) << "\"," << val.size() << ");\n";
|
|
} else {
|
|
out << "const " << c.getCppType() << " " << c.varname()
|
|
<< " = " << escapeCpp(c.value()) << ";\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
static void outputConstants(const char *outputfn,
|
|
const fbvector<PhpConst>& consts) {
|
|
std::ofstream out(outputfn);
|
|
|
|
out << "// @" "generated by gen-class-map.cpp\n"
|
|
<< "#ifndef _H_SYSTEM_CONSTANTS\n"
|
|
<< "#define _H_SYSTEM_CONSTANTS\n"
|
|
<< "namespace HPHP {\n"
|
|
<< "class StaticString;\n"
|
|
<< "class Variant;\n";
|
|
declareConstants(out, consts, true);
|
|
out << "} // namespace HPHP\n"
|
|
<< "#endif // _H_SYSTEM_CONSTANTS\n";
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Class Map
|
|
|
|
#define FUNC_FLAG_MASK (IsProtected|IsPrivate|IsPublic|\
|
|
IsAbstract|IsStatic|IsFinal|HasDocComment|\
|
|
AllowIntercept|NoProfile|ContextSensitive|\
|
|
HipHopSpecific|VariableArguments|\
|
|
RefVariableArguments|MixedVariableArguments|\
|
|
NeedsActRec|FunctionIsFoldable|\
|
|
NoInjection|NoEffect|HasOptFunction)
|
|
|
|
static void writeFunction(std::ostream& out, const PhpFunc& func) {
|
|
auto flags = (func.flags() & FUNC_FLAG_MASK) | IsSystem | IsNothing;
|
|
|
|
if (flags & RefVariableArguments) {
|
|
flags |= VariableArguments;
|
|
}
|
|
if (flags & MixedVariableArguments) {
|
|
flags |= RefVariableArguments | VariableArguments;
|
|
}
|
|
if (!func.isMethod() || !(flags & VISIBILITY_MASK)) {
|
|
flags |= IsPublic;
|
|
}
|
|
if (func.isReturnRef()) {
|
|
flags |= IsReference;
|
|
}
|
|
|
|
out << " " << castLong(flags, true) << ", \"" << func.name() << "\", "
|
|
<< "\"\", "
|
|
<< castLong(0) << ", "
|
|
<< castLong(0) << ",\n";
|
|
|
|
if (flags & HasDocComment) {
|
|
out << " \""
|
|
<< escapeCpp(genDocComment(func, func.className()))
|
|
<< "\",\n";
|
|
}
|
|
|
|
DataType rko = func.returnKindOf();
|
|
if (rko == KindOfAny) {
|
|
// ClassInfo::MethodInfo expects this for Any/Variant
|
|
// TODO: Fix that broken assumption
|
|
rko = KindOfInvalid;
|
|
}
|
|
out << " " << castLong(rko, true) << ",\n";
|
|
for (auto &p : func.params()) {
|
|
long attr = IsNothing;
|
|
DataType ko = p.kindOf();
|
|
if (p.isRef()) {
|
|
// We don't declare param type as KindOfRef
|
|
// as then the caller will try to cast it as such
|
|
attr |= IsReference;
|
|
ko = KindOfAny;
|
|
}
|
|
if (ko == KindOfAny) {
|
|
// TODO: See above
|
|
ko = KindOfInvalid;
|
|
}
|
|
out << " "
|
|
<< castLong(attr, true) << ", "
|
|
<< "\"" << escapeCpp(p.name()) << "\", \"\", "
|
|
<< castLong(ko, true) << ",\n";
|
|
auto ser = p.getDefaultSerialized();
|
|
auto val = p.getDefaultPhp();
|
|
out << " "
|
|
<< "\"" << escapeCpp(ser) << "\", " << castLong(ser.size()) << ", "
|
|
<< "\"" << escapeCpp(val) << "\", " << castLong(val.size()) << ", "
|
|
<< "NULL,\n";
|
|
}
|
|
out << " NULL,\n"
|
|
<< " NULL,\n"
|
|
<< " NULL,\n";
|
|
}
|
|
|
|
static void writeConstant(std::ostream& out, const PhpConst& cns) {
|
|
auto name = cns.name();
|
|
out << " \"" << escapeCpp(name) << "\", ";
|
|
if (cns.hasValue()) {
|
|
auto ser = cns.serialize();
|
|
out << castLong(ser.size())
|
|
<< ", \"" << escapeCpp(ser) << "\",\n";
|
|
return;
|
|
}
|
|
|
|
if (cns.isSystem()) {
|
|
// Special "magic" constants
|
|
if ((name == "SID") || (name == "PHP_SAPI")) {
|
|
out << "(const char *)((offsetof(EnvConstants, k_" << name << ") - "
|
|
<< "offsetof(EnvConstants, stgv_Variant)) / sizeof(Variant)), "
|
|
<< castLong(1) << ",\n";
|
|
return;
|
|
}
|
|
if ((name == "STDIN") || (name == "STDOUT") || (name == "STDERR")) {
|
|
out << "(const char *)&BuiltinFiles::Get" << name << ", NULL,\n";
|
|
return;
|
|
}
|
|
}
|
|
|
|
out << "(const char *)&" << cns.varname() << ", "
|
|
<< castLong((int)cns.kindOf() + 2) << ",\n";
|
|
}
|
|
|
|
#define CLASS_FLAG_MASK (IsAbstract|IsFinal|NoDefaultSweep|\
|
|
HipHopSpecific|HasDocComment)
|
|
#define PROP_FLAG_MASK (IsProtected|IsPrivate|IsPublic|IsStatic)
|
|
|
|
static void writeClass(std::ostream& out, const PhpClass& cls) {
|
|
auto flags = (cls.flags() & CLASS_FLAG_MASK) | IsSystem | IsNothing;
|
|
|
|
out << " " << castLong(flags, true) << ", "
|
|
<< "\"" << escapeCpp(cls.name()) << "\", "
|
|
<< "\"" << escapeCpp(strtolower(cls.parent())) << "\", "
|
|
<< "\"\", "
|
|
<< castLong(0) << ", "
|
|
<< castLong(0) << ",\n";
|
|
|
|
if (flags & HasDocComment) {
|
|
out << " \"" << escapeCpp(genDocComment(cls)) << "\",\n";
|
|
}
|
|
|
|
out << " ";
|
|
for (auto &iface : cls.ifaces()) {
|
|
out << "\"" << escapeCpp(strtolower(iface)) << "\", ";
|
|
}
|
|
out << "NULL,\n";
|
|
|
|
for (auto &method : cls.methods()) {
|
|
writeFunction(out, method);
|
|
}
|
|
out << " NULL,\n";
|
|
|
|
for (auto &prop : cls.properties()) {
|
|
auto propflag = (prop.flags() & PROP_FLAG_MASK) | IsNothing;
|
|
if (!(propflag & VISIBILITY_MASK)) {
|
|
propflag |= IsPublic;
|
|
}
|
|
out << " " << castLong(propflag, true) << ", "
|
|
<< "\"" << escapeCpp(prop.name()) << "\", "
|
|
<< castLong((int)prop.kindOf(), true) << ",\n";
|
|
}
|
|
out << " NULL,\n";
|
|
|
|
for (auto &cns : cls.constants()) {
|
|
writeConstant(out, cns);
|
|
}
|
|
out << " NULL,\n";
|
|
|
|
out << " NULL,\n"; // no attributes
|
|
}
|
|
|
|
static void outputClassMap(const char *outputfn, const char *classmap_name,
|
|
const fbvector<PhpClass>& classes,
|
|
const fbvector<PhpFunc>& funcs,
|
|
const fbvector<PhpConst>& consts) {
|
|
std::ofstream out(outputfn);
|
|
|
|
out << "// @" "generated by gen-class-map.cpp\n"
|
|
<< "#include \"hphp/runtime/base/base_includes.h\"\n"
|
|
<< "#include \"hphp/runtime/ext/ext.h\"\n"
|
|
<< "namespace HPHP {\n";
|
|
declareConstants(out, consts, false);
|
|
out << "const char *" << classmap_name << "[] = {\n"
|
|
<< " (const char *)ClassInfo::IsSystem, NULL, "
|
|
<< "\"\", \"\", NULL, NULL, NULL,\n";
|
|
for (auto &f : funcs) {
|
|
writeFunction(out, f);
|
|
}
|
|
out << " NULL,\n" // End of functions
|
|
<< " NULL,\n"; // End of system "properties"
|
|
for (auto &c : consts) {
|
|
writeConstant(out, c);
|
|
}
|
|
out << " NULL,\n" // End of constants
|
|
<< " NULL,\n"; // End of system "attributes"
|
|
for (auto &c : classes) {
|
|
writeClass(out, c);
|
|
}
|
|
out << " NULL,\n" // End of classes
|
|
<< " NULL,\n" // End of classmap
|
|
<< "};\n"
|
|
<< "} // namespace HPHP\n";
|
|
}
|
|
|
|
void print_usage(const char* program_name) {
|
|
std::cout << "Usage:\n\n"
|
|
<< " " << program_name << "\n"
|
|
<< " --system\n"
|
|
<< " <class map output file>\n"
|
|
<< " <constants output file>\n"
|
|
<< " <*.idl.json>...\n\n"
|
|
<< " " << program_name << "\n"
|
|
<< " <class map name>\n"
|
|
<< " <class map output file>\n"
|
|
<< " <*.idl.json>...\n\n";
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int argc, const char* argv[]) {
|
|
if (argc < 3) {
|
|
print_usage(argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
bool system = !strcmp(argv[1], "--system");
|
|
if (system && argc < 4) {
|
|
print_usage(argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
fbvector<PhpFunc> funcs;
|
|
fbvector<PhpClass> classes;
|
|
fbvector<PhpConst> consts;
|
|
|
|
for (int i = (system ? 4 : 3); i < argc; ++i) {
|
|
try {
|
|
parseIDL(argv[i], funcs, classes, consts);
|
|
} catch (const std::exception& exc) {
|
|
std::cerr << argv[i] << ": " << exc.what() << "\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
const char* path = argv[2];
|
|
const char* name = (system ? "g_class_map" : argv[1]);
|
|
outputClassMap(path, name, classes, funcs, consts);
|
|
if (system) {
|
|
path = argv[3];
|
|
outputConstants(path, consts);
|
|
}
|
|
|
|
return 0;
|
|
}
|