Arquivos
hhvm/hphp/tools/bootstrap/gen-class-map.cpp
T
Benjamin Strahs e35bded5b3 Add hash algos to openssl_verify
A bunch of hash algos are missing from openssl_verify(), this was fixed in PHP ( https://bugs.php.net/patch-display.php?patch=openssl-add-sig-algs.txt&bug_id=61421&revision=1340052451 ) and should be fixed in hhvm
2013-06-18 16:23:25 -07:00

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 &param : 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(GlobalVariables, k_" << name << ") - "
<< "offsetof(GlobalVariables, 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;
}