Objectify and clean up bootstrap programs.

Refactor a lot of idl.h/idl.cpp to be more generic and
make them easier for other bootstrap apps to build on.

This is a precursor for building infotabs/class_map generators
in cpp to remove the need for PHP during bootstrapping.

I'll also be git mving this to hphp/tools/bootstrap
in a follow-up move-only commit.
Esse commit está contido em:
Sara Golemon
2013-05-29 13:58:49 -07:00
commit de sgolemon
commit 6927cf84e4
4 arquivos alterados com 519 adições e 396 exclusões
+125 -167
Ver Arquivo
@@ -30,6 +30,8 @@
#include "hphp/tools/gen-ext-hhvm/idl.h"
using folly::fbstring;
using namespace HPHP::IDL;
using namespace HPHP;
std::unordered_map<fbstring, const PhpFunc*> g_mangleMap;
std::unordered_map<fbstring, const PhpClass*> g_classMap;
@@ -75,22 +77,24 @@ void emitRemappedFuncDecl(const PhpFunc& func,
const fbstring& mangled,
const fbstring& prefix,
std::ostream& out) {
if (isTypeCppIndirectPass(func.returnCppType)) {
if (func.returnCppType == "HPHP::Variant") {
int returnKindOf = func.returnKindOf();
bool indirectReturn = func.isIndirectReturn();
if (indirectReturn) {
if (returnKindOf == KindOfAny) {
out << "TypedValue* ";
} else {
out << "Value* ";
}
} else {
out << func.returnCppType << ' ';
out << func.returnCppType() << ' ';
}
out << prefix << func.getUniqueName() << '(';
bool isFirstParam = true;
if (!g_armMode && isTypeCppIndirectPass(func.returnCppType)) {
if (func.returnCppType == "HPHP::Variant") {
if (!g_armMode && indirectReturn) {
if (func.returnKindOf() == KindOfAny) {
out << "TypedValue* _rv";
} else {
out << "Value* _rv";
@@ -98,7 +102,7 @@ void emitRemappedFuncDecl(const PhpFunc& func,
isFirstParam = false;
}
if (!func.className.empty() && !func.isStatic) {
if (func.usesThis()) {
if (!isFirstParam) {
out << ", ";
}
@@ -106,7 +110,7 @@ void emitRemappedFuncDecl(const PhpFunc& func,
isFirstParam = false;
}
if (func.isVarargs) {
if (func.isVarArgs()) {
if (!isFirstParam) {
out << ", ";
}
@@ -114,26 +118,25 @@ void emitRemappedFuncDecl(const PhpFunc& func,
isFirstParam = false;
}
for (auto const& param : func.params) {
for (auto const& param : func.params()) {
if (!isFirstParam) {
out << ", ";
}
if (isTypeCppIndirectPass(param.cppType)) {
if (param.cppType == "HPHP::Variant" ||
param.cppType == "HPHP::Variant const&" ||
param.cppType == "HPHP::VRefParamValue const&") {
auto kindof = param.kindOf();
if (param.isIndirectPass()) {
if (kindof == KindOfAny || kindof == KindOfRef) {
out << "TypedValue*";
} else {
out << "Value*";
}
} else {
out << param.cppType;
out << param.getCppType();
}
out << ' ' << param.name;
out << ' ' << param.name();
isFirstParam = false;
}
if (func.isVarargs) {
if (func.isVarArgs()) {
assert(!isFirstParam);
out << ", Value* _argv";
}
@@ -147,41 +150,20 @@ void emitCast(const PhpParam& param, int32_t index, std::ostream& out,
const char* ind, bool doCheck) {
if (doCheck) {
out << ind << "if (";
if (param.cppType == "HPHP::String const&") {
if (param.kindOf() == KindOfString) {
out << "!IS_STRING_TYPE((args-" << index << ")->m_type)";
} else {
out << "(args-" << index << ")->m_type != ";
if (param.cppType == "bool") {
out << "KindOfBoolean";
} else if (param.cppType == "int" || param.cppType == "long") {
out << "KindOfInt64";
} else if (param.cppType == "double") {
out << "KindOfDouble";
} else if (param.cppType == "HPHP::Array const&") {
out << "KindOfArray";
} else if (param.cppType == "HPHP::Object const&") {
out << "KindOfObject";
}
out << "(args-" << index << ")->m_type != KindOf"
<< kindOfString(param.kindOf());
}
out << ") {\n";
ind -= 2;
}
out << ind << "tvCastTo";
if (param.cppType == "bool") {
out << "Boolean";
} else if (param.cppType == "int" || param.cppType == "long") {
out << "Int64";
} else if (param.cppType == "double") {
out << "Double";
} else if (param.cppType == "HPHP::String const&") {
out << "String";
} else if (param.cppType == "HPHP::Array const&") {
out << "Array";
} else if (param.cppType == "HPHP::Object const&") {
out << "Object";
if (param.kindOf() != KindOfAny) {
out << ind << "tvCastTo" << kindOfString(param.kindOf())
<< "InPlace(args-" << index << ");\n";
}
out << "InPlace(args-" << index << ");\n";
if (doCheck) {
ind += 2;
@@ -195,11 +177,10 @@ void emitCast(const PhpParam& param, int32_t index, std::ostream& out,
*/
void emitTypechecks(const PhpFunc& func, std::ostream& out, const char* ind) {
bool isFirstParam = true;
for (int k = func.maxNumParams - 1; k >= 0; --k) {
auto const& param = func.params[k];
if (param.cppType == "HPHP::Variant" ||
param.cppType == "HPHP::Variant const&" ||
param.cppType == "HPHP::VRefParamValue const&") {
for (int k = func.numParams() - 1; k >= 0; --k) {
auto const& param = func.param(k);
auto kindof = param.kindOf();
if (kindof == KindOfAny || kindof == KindOfRef) {
continue;
}
@@ -208,25 +189,14 @@ void emitTypechecks(const PhpFunc& func, std::ostream& out, const char* ind) {
}
isFirstParam = false;
bool isOptional = (k >= func.minNumParams);
bool isOptional = (k >= func.minNumParams());
if (isOptional) {
out << "(count <= " << k << " || ";
}
if (param.cppType == "HPHP::String const&") {
if (kindof == KindOfString) {
out << "IS_STRING_TYPE((args - " << k << ")->m_type)";
} else {
out << "(args - " << k << ")->m_type == ";
if (param.cppType == "bool") {
out << "KindOfBoolean";
} else if (param.cppType == "int" || param.cppType == "long") {
out << "KindOfInt64";
} else if (param.cppType == "double") {
out << "KindOfDouble";
} else if (param.cppType == "HPHP::Array const&") {
out << "KindOfArray";
} else if (param.cppType == "HPHP::Object const&") {
out << "KindOfObject";
}
out << "(args - " << k << ")->m_type == KindOf" << kindOfString(kindof);
}
if (isOptional) {
@@ -258,7 +228,7 @@ void emitBuildExtraArgs(const PhpFunc& func, std::ostream& out,
{0}}}
)",
ind,
func.maxNumParams
func.numParams()
);
}
@@ -268,16 +238,16 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
out << prefix << func.getUniqueName() << '(';
bool isFirstParam = true;
if (!g_armMode && isTypeCppIndirectPass(func.returnCppType)) {
if (!g_armMode && func.isIndirectReturn()) {
isFirstParam = false;
if (func.returnCppType == "HPHP::Variant") {
if (func.returnKindOf() == KindOfAny) {
out << "rv";
} else {
out << "&(rv->m_data)";
}
}
if (!func.className.empty() && !func.isStatic) {
if (func.usesThis()) {
if (!isFirstParam) {
out << ", ";
}
@@ -285,7 +255,7 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
out << "(this_)";
}
if (func.isVarargs) {
if (func.isVarArgs()) {
if (!isFirstParam) {
out << ", ";
}
@@ -293,58 +263,54 @@ void emitCallExpression(const PhpFunc& func, const fbstring& prefix,
out << "count";
}
for (auto k = 0; k < func.params.size(); ++k) {
auto const& param = func.params[k];
for (auto k = 0; k < func.numParams(); ++k) {
auto const& param = func.param(k);
if (!isFirstParam) {
out << ", ";
}
isFirstParam = false;
if (!param.defVal.empty()) {
if (param.hasDefault()) {
out << "(count > " << k << ") ? ";
}
if (isTypeCppIndirectPass(param.cppType)) {
if (param.cppType == "HPHP::Variant" ||
param.cppType == "HPHP::Variant const&" ||
param.cppType == "HPHP::VRefParamValue const&") {
if (param.isIndirectPass()) {
auto kindof = param.kindOf();
if (kindof == KindOfAny || kindof == KindOfRef) {
out << "(args-" << k << ')';
} else {
out << "&args[-" << k << "].m_data";
}
} else {
if (param.cppType == "double") {
if (param.kindOf() == KindOfDouble) {
out << "(args[-" << k << "].m_data.dbl)";
} else {
out << '(' << param.cppType << ")(args[-" << k << "].m_data.num)";
out << '(' << param.getCppType() << ")(args[-" << k << "].m_data.num)";
}
}
if (!param.defVal.empty()) {
if (param.hasDefault()) {
out << " : ";
if (param.defValNeedsVariable()) {
if (param.cppType == "HPHP::Variant" ||
param.cppType == "HPHP::Variant const&" ||
param.cppType == "HPHP::VRefParamValue const&") {
auto kindof = param.kindOf();
if (param.defValueNeedsVariable()) {
if (kindof == KindOfAny || kindof == KindOfRef) {
out << "(TypedValue*)(&defVal" << k << ')';
} else {
out << "(Value*)(&defVal" << k << ')';
}
} else if (isTypeCppIndirectPass(param.cppType)) {
if (param.cppType == "HPHP::Variant" ||
param.cppType == "HPHP::Variant const&" ||
param.cppType == "HPHP::VRefParamValue const&") {
out << "(TypedValue*)(&" << param.defVal << ')';
} else if (param.isIndirectPass()) {
if (kindof == KindOfAny || kindof == KindOfRef) {
out << "(TypedValue*)(&" << param.getDefault() << ')';
} else {
out << "(Value*)(&" << param.defVal << ')';
out << "(Value*)(&" << param.getDefault() << ')';
}
} else {
out << '(' << param.cppType << ")(" << param.defVal << ')';
out << '(' << param.getCppType() << ")(" << param.getDefault() << ')';
}
}
}
if (func.isVarargs) {
if (func.isVarArgs()) {
assert(!isFirstParam);
out << ", (Value*)(&extraArgs)";
}
@@ -364,60 +330,56 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
// Set up the type of the return value, and emit post-call code to normalize
// return types and values
if (func.returnCppType == "bool") {
auto returnKindOf = func.returnKindOf();
if (returnKindOf == KindOfBoolean) {
out << ind << "rv->m_type = KindOfBoolean;\n";
call_prefix = "rv->m_data.num = (";
call_suffix = ") ? 1LL : 0LL;\n";
} else if (func.returnCppType == "int" || func.returnCppType == "long") {
} else if (returnKindOf == KindOfInt64) {
out << ind << "rv->m_type = KindOfInt64;\n";
call_prefix = "rv->m_data.num = (int64_t)";
call_suffix = ";\n";
} else if (func.returnCppType == "double") {
} else if (returnKindOf == KindOfDouble) {
out << ind << "rv->m_type = KindOfDouble;\n";
call_prefix = "rv->m_data.dbl = ";
call_suffix = ";\n";
} else if (func.returnCppType == "void") {
} else if (returnKindOf == KindOfInvalid || returnKindOf == KindOfNull) {
out << ind << "rv->m_type = KindOfNull;\n";
call_suffix = ";\n";
} else if (func.returnCppType == "HPHP::String") {
} else if (returnKindOf == KindOfString) {
out << ind << "rv->m_type = KindOfString;\n";
call_suffix = (fbstring(";\n") + ind +
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
} else if (func.returnCppType == "HPHP::Array") {
} else if (returnKindOf == KindOfArray) {
out << ind << "rv->m_type = KindOfArray;\n";
call_suffix = (fbstring(";\n") + ind +
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
} else if (func.returnCppType == "HPHP::Object") {
} else if (returnKindOf == KindOfObject) {
out << ind << "rv->m_type = KindOfObject;\n";
call_suffix = (fbstring(";\n") + ind +
"if (rv->m_data.num == 0LL) rv->m_type = KindOfNull;\n");
} else if (func.returnCppType == "HPHP::Variant") {
} else {
call_suffix = (fbstring(";\n") + ind +
"if (rv->m_type == KindOfUninit) "
"rv->m_type = KindOfNull;\n");
}
if (func.isVarargs) {
if (func.isVarArgs()) {
emitBuildExtraArgs(func, out, ind);
}
// If any default values need variables (because they have nontrivial values),
// declare and initialize those
for (auto k = 0; k < func.params.size(); ++k) {
auto const& param = func.params[k];
if (param.defValNeedsVariable()) {
auto type = param.cppType;
if (type.compare(type.length() - 7, 7, " const&") == 0) {
type = type.substr(0, type.length() - 7);
}
if (type.compare(0, 6, "HPHP::") == 0) {
type = type.substr(6);
}
out << ind << type << " defVal" << k;
if (type != "Variant" ||
(param.defVal != "null" && param.defVal != "null_variant")) {
for (auto k = 0; k < func.numParams(); ++k) {
auto const& param = func.param(k);
if (param.defValueNeedsVariable()) {
DataType kindof = param.kindOf();
out << ind << param.getStrippedCppType() << " defVal" << k;
fbstring defVal = param.getDefault();
if (kindof != KindOfAny ||
(defVal != "null" && defVal != "null_variant")) {
out << " = ";
out << (param.defVal == "null" ? "uninit_null()" : param.defVal);
out << (defVal == "null" ? "uninit_null()" : defVal);
}
out << ";\n";
}
@@ -426,7 +388,7 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
// Put the return-value-space pointer into x8
if (g_armMode) {
out << ind << "asm volatile (\"mov x8, %0\\n\" : : \"r\"(";
if (func.returnCppType == "HPHP::Variant") {
if (func.returnKindOf() == KindOfAny) {
out << "rv";
} else {
out << "&(rv->m_data)";
@@ -435,29 +397,29 @@ void emitExtCall(const PhpFunc& func, std::ostream& out, const char* ind) {
}
out << ind << call_prefix;
emitCallExpression(func, func.className.empty() ? "fh_" : "th_", out);
emitCallExpression(func, func.isMethod() ? "th_" : "fh_", out);
out << call_suffix;
}
void emitCasts(const PhpFunc& func, std::ostream& out, const char* ind) {
assert(func.numTypeChecks > 0);
assert(func.numTypeChecks() > 0);
if (func.numTypeChecks == 1) {
for (auto i = func.maxNumParams - 1; i >= 0; --i) {
if (func.params[i].isCheckedType()) {
emitCast(func.params[i], i, out, ind, false);
if (func.numTypeChecks() == 1) {
for (auto i = func.numParams() - 1; i >= 0; --i) {
if (func.param(i).isCheckedType()) {
emitCast(func.param(i), i, out, ind, false);
return;
}
}
assert(false); // not reached
}
if (func.minNumParams != func.maxNumParams) {
if (func.minNumParams() != func.numParams()) {
out << ind << "switch (count) {\n";
for (auto i = func.maxNumParams - 1; i >= func.minNumParams; --i) {
auto const& param = func.params[i];
if (i == func.maxNumParams - 1) {
out << ind << "default: // count >= " << func.maxNumParams << '\n';
for (auto i = func.numParams() - 1; i >= func.minNumParams(); --i) {
auto const& param = func.param(i);
if (i == func.numParams() - 1) {
out << ind << "default: // count >= " << func.numParams() << '\n';
} else {
out << ind << "case " << (i + 1) << ":\n";
}
@@ -465,12 +427,12 @@ void emitCasts(const PhpFunc& func, std::ostream& out, const char* ind) {
emitCast(param, i, out, ind - 2, true);
}
}
out << ind << "case " << func.minNumParams << ":\n";
out << ind << "case " << func.minNumParams() << ":\n";
out << ind << " break;\n";
out << ind << "}\n";
}
for (auto i = func.minNumParams - 1; i >= 0; --i) {
auto const& param = func.params[i];
for (auto i = func.minNumParams() - 1; i >= 0; --i) {
auto const& param = func.param(i);
if (param.isCheckedType()) {
emitCast(param, i, out, ind, true);
}
@@ -487,14 +449,14 @@ void emitSlowPathHelper(const PhpFunc& func, const fbstring& prefix,
std::ostream& out) {
out << "void " << prefix << func.getUniqueName()
<< "(TypedValue* rv, ActRec* ar, int32_t count";
if (func.isMethod() && !func.isStatic) {
if (func.usesThis()) {
out << ", ObjectData* this_";
}
out << ") __attribute__((noinline,cold));\n";
out << "void " << prefix << func.getUniqueName()
<< "(TypedValue* rv, ActRec* ar, int32_t count";
if (func.isMethod() && !func.isStatic) {
if (func.usesThis()) {
out << ", ObjectData* this_";
}
out << ") {\n";
@@ -539,22 +501,19 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
}
auto& func = *idlIt->second;
bool isMethod = !func.className.empty();
bool isMethod = func.isMethod();
auto classIt = g_classMap.find(func.className);
if (isMethod && func.name == "__construct" &&
classIt != g_classMap.end()) {
auto classIt = g_classMap.find(func.className());
if (func.isCtor() && classIt != g_classMap.end()) {
auto& klass = *classIt->second;
auto& flags = klass.flags;
if (std::find(flags.begin(), flags.end(), "IsCppAbstract") == flags.end()) {
emitCtorHelper(klass.name, cpp);
if (!(klass.flags() & IsCppAbstract)) {
emitCtorHelper(klass.name(), cpp);
}
if (std::find(flags.begin(), flags.end(), "NoDefaultSweep")
!= flags.end()) {
cpp << "IMPLEMENT_CLASS_NO_DEFAULT_SWEEP(" << klass.name << ");\n";
if (klass.flags() & NoDefaultSweep) {
cpp << "IMPLEMENT_CLASS_NO_DEFAULT_SWEEP(" << klass.name() << ");\n";
} else {
cpp << "IMPLEMENT_CLASS(" << klass.name << ");\n";
cpp << "IMPLEMENT_CLASS(" << klass.name() << ");\n";
}
}
@@ -569,7 +528,7 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
}
cpp << decl.str();
if (func.numTypeChecks > 0) {
if (func.numTypeChecks() > 0) {
emitSlowPathHelper(func, slowPathPrefix, cpp);
}
@@ -584,7 +543,7 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
cpp << in << "int32_t count = ar->numArgs();\n";
cpp << in << "TypedValue* args UNUSED = ((TypedValue*)ar) - 1;\n";
if (func.isMethod() && !func.isStatic) {
if (func.usesThis()) {
cpp << in
<< "ObjectData* this_ = (ar->hasThis() ? ar->getThis() : nullptr);\n";
cpp << in << "if (this_) {\n";
@@ -593,27 +552,27 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
// Check the arg count
bool needArgMiscountClause = false;
if (func.isVarargs) {
if (func.minNumParams > 0) {
cpp << in << "if (count >= " << func.minNumParams << ") {\n";
if (func.isVarArgs()) {
if (func.minNumParams() > 0) {
cpp << in << "if (count >= " << func.minNumParams() << ") {\n";
needArgMiscountClause = true;
in -= 2;
}
} else {
if (func.minNumParams == func.maxNumParams) {
cpp << in << "if (count == " << func.minNumParams << ") {\n";
} else if (func.minNumParams == 0) {
cpp << in << "if (count <= " << func.maxNumParams << ") {\n";
if (func.minNumParams() == func.numParams()) {
cpp << in << "if (count == " << func.minNumParams() << ") {\n";
} else if (func.minNumParams() == 0) {
cpp << in << "if (count <= " << func.numParams() << ") {\n";
} else {
cpp << in << "if (count >= " << func.minNumParams
<< " && count <= "<< func.maxNumParams << ") {\n";
cpp << in << "if (count >= " << func.minNumParams()
<< " && count <= "<< func.numParams() << ") {\n";
}
needArgMiscountClause = true;
in -= 2;
}
// Count is OK. Check arg types
if (func.numTypeChecks > 0) {
if (func.numTypeChecks() > 0) {
cpp << in << "if (";
emitTypechecks(func, cpp, in);
cpp << ") {\n";
@@ -624,10 +583,10 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
emitExtCall(func, cpp, in);
// Deal with type mismatches: punt to fg1_
if (func.numTypeChecks > 0) {
if (func.numTypeChecks() > 0) {
cpp << in + 2 << "} else {\n";
cpp << in << slowPathPrefix << func.getUniqueName() << "(rv, ar, count";
if (func.isMethod() && !func.isStatic) {
if (func.usesThis()) {
cpp << ", this_";
}
cpp << ");\n";
@@ -637,17 +596,17 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
if (needArgMiscountClause) {
cpp << in + 2 << "} else {\n";
if (func.isVarargs) {
if (func.isVarArgs()) {
cpp << in << "throw_missing_arguments_nr(\"" << func.getPrettyName()
<< "\", " << func.minNumParams << ", count, 1);\n";
<< "\", " << func.minNumParams() << ", count, 1);\n";
} else {
if (func.minNumParams == 0) {
if (func.minNumParams() == 0) {
cpp << in << "throw_toomany_arguments_nr(\"" << func.getPrettyName()
<< "\", " << func.maxNumParams << ", 1);\n";
<< "\", " << func.numParams() << ", 1);\n";
} else {
cpp << in << "throw_wrong_arguments_nr(\"" << func.getPrettyName()
<< "\", count, " << func.minNumParams << ", "
<< func.maxNumParams << ", 1);\n";
<< "\", count, " << func.minNumParams() << ", "
<< func.numParams() << ", 1);\n";
}
}
cpp << in << "rv->m_data.num = 0LL;\n";
@@ -656,18 +615,17 @@ void processSymbol(const fbstring& symbol, std::ostream& header,
cpp << in << "}\n";
}
if (func.isMethod() && !func.isStatic) {
if (func.isMethod() && !func.isStatic()) {
cpp << in + 2 << "} else {\n";
cpp << in << "throw_instance_method_fatal(\"" << func.className
<< "::" << func.name << "\");\n";
cpp << in << "throw_instance_method_fatal(\"" << func.className()
<< "::" << func.name() << "\");\n";
in += 2;
cpp << in << "}\n";
}
auto numLocals = func.maxNumParams;
bool noThis = (func.className.empty() || func.isStatic);
auto numLocals = func.numParams();
auto frameFree =
(noThis ? "frame_free_locals_no_this_inl" : "frame_free_locals_inl");
func.usesThis() ? "frame_free_locals_inl" : "frame_free_locals_no_this_inl";
cpp << in << frameFree << "(ar, " << numLocals << ");\n";
cpp << in << "memcpy(&ar->m_r, rv, sizeof(TypedValue));\n";
cpp << in << "return &ar->m_r;\n";
@@ -703,8 +661,8 @@ int main(int argc, const char* argv[]) {
g_mangleMap[func.getCppSig()] = &func;
}
for (auto const& klass : classes) {
g_classMap[klass.name] = &klass;
for (auto const& func : klass.methods) {
g_classMap[klass.name()] = &klass;
for (auto const& func : klass.methods()) {
g_mangleMap[func.getCppSig()] = &func;
}
}
+21 -22
Ver Arquivo
@@ -27,7 +27,7 @@
using folly::fbstring;
using folly::fbvector;
using namespace HPHP::IDL;
int main(int argc, const char* argv[]) {
if (argc < 3) {
@@ -64,16 +64,15 @@ int main(int argc, const char* argv[]) {
// Declare the fg_ and tg_ stubs
for (auto const& func : funcs) {
cpp << "TypedValue* fg_" << func.name << "(ActRec* ar);\n";
cpp << "TypedValue* fg_" << func.name() << "(ActRec* ar);\n";
}
for (auto const& klass : classes) {
if (std::find(klass.flags.begin(), klass.flags.end(), "IsCppAbstract")
== klass.flags.end()) {
cpp << "Instance* new_" << klass.name << "_Instance(Class*);\n";
classesWithCtors.insert(klass.name);
if (!(klass.flags() & IsCppAbstract)) {
cpp << "Instance* new_" << klass.name() << "_Instance(Class*);\n";
classesWithCtors.insert(klass.name());
}
for (auto const& func : klass.methods) {
for (auto const& func : klass.methods()) {
cpp << "TypedValue* tg_" << func.getUniqueName()
<< "(ActRec* ar);\n";
}
@@ -89,7 +88,7 @@ int main(int argc, const char* argv[]) {
bool first = true;
for (auto const& func : funcs) {
if (!func.className.empty()) {
if (func.isMethod()) {
continue;
}
if (!first) {
@@ -97,24 +96,24 @@ int main(int argc, const char* argv[]) {
}
first = false;
cpp << "{ \"" << func.name << "\", fg_" << func.name
<< ", (void *)&fh_" << func.name << " }";
cpp << "{ \"" << func.name() << "\", fg_" << func.name()
<< ", (void *)&fh_" << func.name() << " }";
}
cpp << "\n};\n\n";
for (auto const& klass : classes) {
cpp << "static const long long hhbc_ext_method_count_" << klass.name
<< " = " << klass.methods.size() << ";\n";
cpp << "static const HhbcExtMethodInfo hhbc_ext_methods_" << klass.name
cpp << "static const long long hhbc_ext_method_count_" << klass.name()
<< " = " << klass.numMethods() << ";\n";
cpp << "static const HhbcExtMethodInfo hhbc_ext_methods_" << klass.name()
<< "[] = {\n ";
first = true;
for (auto const& method : klass.methods) {
for (auto const& method : klass.methods()) {
if (!first) {
cpp << ",\n ";
}
first = false;
cpp << "{ \"" << method.name << "\", tg_" << method.getUniqueName()
cpp << "{ \"" << method.name() << "\", tg_" << method.getUniqueName()
<< " }";
}
cpp << "\n};\n\n";
@@ -129,15 +128,15 @@ int main(int argc, const char* argv[]) {
}
first = false;
auto ctor = (classesWithCtors.count(klass.name) > 0
? fbstring("new_") + klass.name + "_Instance"
auto ctor = (classesWithCtors.count(klass.name()) > 0
? fbstring("new_") + klass.name() + "_Instance"
: fbstring("nullptr"));
cpp << "{ \"" << klass.name << "\", " << ctor
<< ", sizeof(c_" << klass.name << ')'
<< ", hhbc_ext_method_count_" << klass.name
<< ", hhbc_ext_methods_" << klass.name
<< ", &c_" << klass.name << "::s_cls }";
cpp << "{ \"" << klass.name() << "\", " << ctor
<< ", sizeof(c_" << klass.name() << ')'
<< ", hhbc_ext_method_count_" << klass.name()
<< ", hhbc_ext_methods_" << klass.name()
<< ", &c_" << klass.name() << "::s_cls }";
}
cpp << "\n};\n\n";
cpp << "} // namespace HPHP\n";
+205 -148
Ver Arquivo
@@ -23,187 +23,248 @@
#include "folly/Format.h"
#include "folly/json.h"
namespace HPHP { namespace IDL {
/////////////////////////////////////////////////////////////////////////////
const std::unordered_map<fbstring, fbstring> g_typeMap =
static const std::unordered_map<fbstring, DataType> g_kindOfMap =
{
{"Boolean", "bool"},
{"Int32", "int"},
{"Int64", "long"},
{"Double", "double"},
{"String", "HPHP::String"},
{"Int64Vec", "HPHP::Array"},
{"StringVec", "HPHP::Array"},
{"VariantVec", "HPHP::Array"},
{"Int64Map", "HPHP::Array"},
{"StringMap", "HPHP::Array"},
{"VariantMap", "HPHP::Array"},
{"Object", "HPHP::Object"},
{"Resource", "HPHP::Object"},
{"Variant", "HPHP::Variant"},
{"Numeric", "HPHP::Variant"},
{"Primitive", "HPHP::Variant"},
{"PlusOperand", "HPHP::Variant"},
{"Sequence", "HPHP::Variant"},
{"Any", "HPHP::Variant"},
{"Boolean", KindOfBoolean},
{"Int32", KindOfInt64},
{"Int64", KindOfInt64},
{"Double", KindOfDouble},
{"String", KindOfString},
{"Int64Vec", KindOfArray},
{"StringVec", KindOfArray},
{"VariantVec", KindOfArray},
{"Int64Map", KindOfArray},
{"StringMap", KindOfArray},
{"VariantMap", KindOfArray},
{"Object", KindOfObject},
{"Resource", KindOfObject},
{"Variant", KindOfAny},
{"Numeric", KindOfAny},
{"Primitive", KindOfAny},
{"PlusOperand", KindOfAny},
{"Sequence", KindOfAny},
{"Any", KindOfAny},
};
const std::unordered_set<fbstring> g_knownStringConstants =
static const std::unordered_map<int, fbstring> g_typeMap =
{
{(int)KindOfInvalid, "void"},
{(int)KindOfBoolean, "bool"},
{(int)KindOfInt64, "long"},
{(int)KindOfDouble, "double"},
{(int)KindOfString, "HPHP::String"},
{(int)KindOfArray, "HPHP::Array"},
{(int)KindOfObject, "HPHP::Object"},
{(int)KindOfAny, "HPHP::Variant"},
};
static const std::unordered_map<fbstring, FuncFlags> g_flagsMap =
{
{"IsAbstract", IsAbstract},
{"IsFinal", IsFinal},
{"IsPublic", IsPublic},
{"IsProtected", IsProtected},
{"IsPrivate", IsPrivate},
{"IgnoreRedefinition", IgnoreRedefinition},
{"IsStatic", IsStatic},
{"IsCppAbstract", IsCppAbstract},
{"IsReference", IsReference},
{"IsConstructor", IsConstructor},
{"IsNothing", IsNothing},
{"HasDocComment", HasDocComment},
{"HipHopSpecific", HipHopSpecific},
{"VariableArguments", VariableArguments},
{"RefVariableArguments", RefVariableArguments},
{"MixedVariableArguments", MixedVariableArguments},
{"FunctionIsFoldable", FunctionIsFoldable},
{"NoEffect", NoEffect},
{"NoInjection", NoInjection},
{"HasOptFunction", HasOptFunction},
{"AllowIntercept", AllowIntercept},
{"NoProfile", NoProfile},
{"ContextSensitive", ContextSensitive},
{"NoDefaultSweep", NoDefaultSweep},
{"IsSystem", IsSystem},
{"IsTrait", IsTrait},
{"NeedsActRec", NeedsActRec},
};
static const std::unordered_set<fbstring> g_knownStringConstants =
{ "k_HPHP_TRIM_CHARLIST" };
bool isTypeCppIndirectPass(const fbstring& type) {
return (type != "bool" &&
type != "int" &&
type != "long" &&
type != "double" &&
type != "void");
bool isKindOfIndirect(DataType kindof) {
return (kindof != KindOfBoolean) &&
(kindof != KindOfInt64) &&
(kindof != KindOfDouble) &&
(kindof != KindOfInvalid);
}
fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
if (!typeNode.isString()) {
return "void";
static DataType kindOfFromDynamic(const folly::dynamic& t) {
if (!t.isString()) {
return KindOfInvalid;
}
auto it = g_kindOfMap.find(t.asString());
if (it == g_kindOfMap.end()) {
return KindOfObject;
}
auto typeIt = g_typeMap.find(typeNode.asString());
if (typeIt == g_typeMap.end()) {
return (isReturnType ? "HPHP::Object" : "HPHP::Object const&");
return it->second;
}
static fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) {
if (typeNode == "Int32") {
return "int";
}
auto& type = typeIt->second;
if (!isReturnType && isTypeCppIndirectPass(type)) {
DataType kindof = kindOfFromDynamic(typeNode);
auto it = g_typeMap.find((int)kindof);
assert(it != g_typeMap.end());
auto& type = it->second;
if (!isReturnType && isKindOfIndirect(kindof)) {
return type + " const&";
} else {
return type;
}
}
bool PhpParam::defValNeedsVariable() const {
if (defVal.empty() || !isTypeCppIndirectPass(cppType)) {
static unsigned long parseFlags(const folly::dynamic &flags) {
if (flags.isNull()) {
return 0;
}
if (!flags.isArray()) {
throw std::logic_error("'flags' field must be an array");
}
unsigned long ret = 0;
for (auto &flag : flags) {
auto f = g_flagsMap.find(flag.asString());
if (f == g_flagsMap.end()) {
continue;
}
ret |= f->second;
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////
// PhpParam
PhpParam::PhpParam(const folly::dynamic& param,
bool isMagicMethod /*= false */) :
m_name(param["name"].asString()),
m_param(param) {
if (isMagicMethod) {
m_kindOf = KindOfAny;
m_cppType = "HPHP::Variant";
return;
}
if (isRef()) {
m_kindOf = KindOfRef;
m_cppType = "HPHP::VRefParamValue const&";
} else {
m_kindOf = kindOfFromDynamic(param["type"]);
m_cppType = typeString(param["type"], false);
}
}
bool PhpParam::defValueNeedsVariable() const {
DataType cppKindOf = kindOf();
if (!hasDefault() || !isIndirectPass()) {
return false;
}
if (cppType == "HPHP::String const&" && (defVal == "empty_string" ||
defVal == "null_string")) {
return false;
} else if (cppType == "HPHP::String const&" &&
g_knownStringConstants.count(defVal) > 0) {
return false;
} else if (cppType == "HPHP::Array const&" && defVal == "null_array") {
return false;
} else if (cppType == "HPHP::Object const&" && defVal == "null_object") {
return false;
} else if (cppType == "HPHP::Variant const&" && defVal == "null_variant") {
fbstring defVal = getDefault();
if (cppKindOf == KindOfString &&
((defVal == "empty_string") ||
(defVal == "null_string") ||
(g_knownStringConstants.count(defVal) > 0))) {
return false;
}
if ((cppKindOf == KindOfArray) && (defVal == "null_array")) {
return false;
}
if ((cppKindOf == KindOfObject) && (defVal == "null_object")) {
return false;
}
if ((cppKindOf == KindOfAny) && (defVal == "null_variant")) {
return false;
}
return true;
}
PhpFunc PhpFunc::fromDynamic(const folly::dynamic& d,
const fbstring& className) {
/////////////////////////////////////////////////////////////////////////////
// PhpFunc
PhpFunc::PhpFunc(const folly::dynamic& d,
const fbstring& className) :
m_name(d["name"].asString()),
m_className(className),
m_func(d),
m_returnRef(d.getDefault("ref", "false") == "true"),
m_returnKindOf(m_returnRef ? KindOfRef :
kindOfFromDynamic(d["return"]["type"])),
m_returnCppType(typeString(d["return"]["type"], true)),
m_minNumParams(0),
m_numTypeChecks(0) {
// Better at least have a name
auto name = d["name"].asString();
auto args = d.find("args");
auto flags = d.find("flags");
auto ret = d.find("return");
if (args == d.items().end() || !args->second.isArray()) {
throw std::logic_error(
folly::format("'{0}' must have an array field 'args'", name).str()
);
}
if (flags == d.items().end() || !flags->second.isArray()) {
throw std::logic_error(
folly::format("'{0}' must have an array field 'flags'", name).str()
folly::format("'{0}' must have an array field 'args'", name()).str()
);
}
auto ret = d.find("return");
if (ret == d.items().end() || !ret->second.isObject() ||
ret->second.find("type") == ret->second.items().end()) {
throw std::logic_error(
folly::format("'{0}' must have an array field 'return', which must have "
"a string field 'type'", name).str()
"a string field 'type'", name()).str()
);
}
auto areVarargs = [](const fbstring& str) {
return (str == "VariableArguments" ||
str == "RefVariableArguments" ||
str == "MixedVariableArguments");
};
fbvector<PhpParam> params;
try {
params = std::move(folly::convertTo<fbvector<PhpParam>>(args->second));
} catch (const std::exception& exc) {
throw std::logic_error(
folly::format("'{0}' has an arg with either 'name' or 'type' field "
"missing", name).str()
);
}
if (name == "__get" ||
name == "__set" ||
name == "__isset" ||
name == "__unset" ||
name == "__call") {
for (auto& param : params) {
param.cppType = "HPHP::Variant";
}
}
auto refIt = d.find("ref");
bool ref = (refIt != d.items().end() && refIt->second.asString() == "true");
PhpFunc retval;
retval.name = name;
retval.className = className;
retval.returnCppType = typeString(ret->second["type"], true);
retval.returnByRef = ref;
retval.params = params;
retval.isVarargs = anyFlags(areVarargs, flags->second);
retval.isStatic = false;
if (!className.empty()) {
auto areStatic = [](const fbstring& str) {
return str == "IsStatic";
};
retval.isStatic = anyFlags(areStatic, flags->second);
}
retval.initComputedProps();
return retval;
}
void PhpFunc::initComputedProps() {
maxNumParams = params.size();
minNumParams = params.size();
numTypeChecks = 0;
for (auto const& param : params) {
if (!param.defVal.empty()) {
--minNumParams;
bool magic = isMagicMethod();
for (auto &p : args->second) {
PhpParam param(p, magic);
m_params.push_back(param);
if (!param.hasDefault()) {
++m_minNumParams;
}
if (param.isCheckedType()) {
++numTypeChecks;
++m_numTypeChecks;
}
}
m_flags = parseFlags(m_func["flags"]);
}
fbstring PhpFunc::getCppSig() const {
std::ostringstream out;
auto lowername = name;
std::transform(name.begin(), name.end(), lowername.begin(),
fbstring nm = name();
fbstring lowername = nm;
std::transform(nm.begin(), nm.end(), lowername.begin(),
std::ptr_fun<int, int>(std::tolower));
if (className.empty()) {
if (!isMethod()) {
out << "HPHP::f_" << lowername << "(";
} else {
if (isStatic) {
out << "HPHP::c_" << className << "::ti_" << lowername << "(";
if (isStatic()) {
out << "HPHP::c_" << className() << "::ti_" << lowername << "(";
} else {
out << "HPHP::c_" << className << "::t_" << lowername << "(";
out << "HPHP::c_" << className() << "::t_" << lowername << "(";
}
}
bool firstParam = true;
if (isVarargs) {
if (isVarArgs()) {
if (!firstParam) {
out << ", ";
}
@@ -211,15 +272,15 @@ fbstring PhpFunc::getCppSig() const {
firstParam = false;
}
for (auto const& param : params) {
for (auto const& param : m_params) {
if (!firstParam) {
out << ", ";
}
out << param.cppType;
out << param.getCppType();
firstParam = false;
}
if (isVarargs) {
if (isVarArgs()) {
assert(!firstParam);
out << ", HPHP::Array const&";
}
@@ -228,20 +289,21 @@ fbstring PhpFunc::getCppSig() const {
return out.str();
}
bool anyFlags(std::function<bool(const fbstring&)> pred,
const folly::dynamic& flagsArray) {
if (!flagsArray.isArray()) {
return false;
/////////////////////////////////////////////////////////////////////////////
// PhpClass
PhpClass::PhpClass(const folly::dynamic &c) :
m_class(c),
m_name(c["name"].asString()) {
for (auto const& f : c["funcs"]) {
PhpFunc func(f, m_name);
m_methods.push_back(func);
}
for (auto const& strDyn : flagsArray) {
auto str = strDyn.asString();
if (pred(str)) {
return true;
}
}
return false;
m_flags = parseFlags(m_class["flags"]);
}
/////////////////////////////////////////////////////////////////////////////
void parseIDL(const char* idlFilePath,
fbvector<PhpFunc>& funcVec,
fbvector<PhpClass>& classVec) {
@@ -252,19 +314,14 @@ void parseIDL(const char* idlFilePath,
auto parsed = folly::parseJson(jsonString.str());
for (auto const& f : parsed["funcs"]) {
auto func = PhpFunc::fromDynamic(f, "");
PhpFunc func(f, "");
funcVec.push_back(func);
}
for (auto const& c : parsed["classes"]) {
PhpClass klass;
klass.name = c["name"].asString();
klass.flags = folly::convertTo<fbvector<fbstring>>(c["flags"]);
for (auto const& f : c["funcs"]) {
auto func = PhpFunc::fromDynamic(f, c["name"].asString());
klass.methods.push_back(func);
}
PhpClass klass(c);
classVec.push_back(klass);
}
}
/////////////////////////////////////////////////////////////////////////////
}} // namespace HPHP::IDL
+168 -59
Ver Arquivo
@@ -22,101 +22,210 @@
#include "folly/FBString.h"
#include "folly/FBVector.h"
#include "hphp/runtime/base/datatype.h"
using folly::fbstring;
using folly::fbvector;
namespace HPHP { namespace IDL {
/////////////////////////////////////////////////////////////////////////////
bool isTypeCppIndirectPass(const fbstring& type);
enum FuncFlags {
IsAbstract = (1 << 4),
IsFinal = (1 << 5),
IsPublic = (1 << 6),
IsProtected = (1 << 7),
IsPrivate = (1 << 8),
IgnoreRedefinition = (1 << 8),
IsStatic = (1 << 9),
IsCppAbstract = (1 << 10),
IsReference = (1 << 11),
IsConstructor = (1 << 12),
IsNothing = (1 << 13),
HasDocComment = (1 << 14),
HipHopSpecific = (1 << 16),
VariableArguments = (1 << 17),
RefVariableArguments = (1 << 18),
MixedVariableArguments = (1 << 19),
FunctionIsFoldable = (1 << 20),
NoEffect = (1 << 21),
NoInjection = (1 << 22),
HasOptFunction = (1 << 23),
AllowIntercept = (1 << 24),
NoProfile = (1 << 25),
ContextSensitive = (1 << 26),
NoDefaultSweep = (1 << 27),
IsSystem = (1 << 28),
IsTrait = (1 << 29),
NeedsActRec = (1 << 31),
};
fbstring typeString(const folly::dynamic& typeNode, bool isReturnType);
#define VarArgsMask (VariableArguments | \
RefVariableArguments | \
MixedVariableArguments)
struct PhpParam {
fbstring name;
fbstring cppType;
fbstring defVal;
bool byRef;
bool isKindOfIndirect(DataType kindof);
static inline fbstring kindOfString(DataType t) {
switch (t) {
case KindOfAny: return "Any";
case KindOfUnknown: return "Unknown";
case KindOfNull: return "Null";
case KindOfBoolean: return "Boolean";
case KindOfInt64: return "Int64";
case KindOfDouble: return "Double";
case KindOfStaticString: return "StaticString";
case KindOfString: return "String";
case KindOfArray: return "Array";
case KindOfObject: return "Object";
case KindOfRef: return "Ref";
default:
// No other enums should occur in IDL parsing
assert(false);
return "";
}
}
class PhpParam {
public:
explicit PhpParam(const folly::dynamic& param, bool isMagicMethod = false);
fbstring name() const { return m_name; }
fbstring getCppType() const { return m_cppType; }
fbstring getStrippedCppType() const {
fbstring ret = m_cppType;
if (!ret.compare(0, 6, "HPHP::")) {
ret = ret.substr(6);
}
if (!ret.compare(ret.length() - 7, 7, " const&")) {
ret = ret.substr(0, ret.length() - 7);
}
return ret;
}
DataType kindOf() const { return m_kindOf; }
bool isRef() const { return m_param.getDefault("ref", false).asBool(); }
bool hasDefault() const {
return m_param.find("value") != m_param.items().end();
}
fbstring getDefault() const {
return hasDefault() ? m_param["value"].asString() : "";
}
bool isCheckedType() const {
return (cppType != "HPHP::Variant" &&
cppType != "HPHP::VRefParamValue const&" &&
cppType != "HPHP::Variant const&");
return !isRef() && (kindOf() != KindOfAny);
}
bool defValueNeedsVariable() const;
bool defValNeedsVariable() const;
bool isIndirectPass() const { return isKindOfIndirect(kindOf()); }
private:
fbstring m_name;
folly::dynamic m_param;
DataType m_kindOf;
fbstring m_cppType;
};
namespace folly {
template<>
struct DynamicConverter<PhpParam> {
static PhpParam convert(const dynamic& d) {
auto refIt = d.find("ref");
bool ref = (refIt != d.items().end() && refIt->second.asBool());
auto valIt = d.find("value");
auto value = (valIt != d.items().end() ? valIt->second.asString() : "");
auto type =
(ref ? "HPHP::VRefParamValue const&" : typeString(d["type"], false));
class PhpFunc {
public:
PhpFunc(const folly::dynamic& d, const fbstring& className);
return {d["name"].asString(), type, value, ref};
}
};
} // namespace folly
struct PhpFunc {
fbstring name;
fbstring className;
fbstring returnCppType;
bool returnByRef;
fbvector<PhpParam> params;
bool isVarargs;
bool isStatic;
// Computed properties.
int minNumParams;
int maxNumParams;
int numTypeChecks;
static PhpFunc fromDynamic(const folly::dynamic& d,
const fbstring& className);
fbstring name() const { return m_name; }
fbstring className() const { return m_className; }
bool isMethod() const {
return !className.empty();
return !m_className.empty();
}
bool isMagicMethod() const {
return (isMethod() && (
(m_name == "__get") ||
(m_name == "__set") ||
(m_name == "__isset") ||
(m_name == "__unset") ||
(m_name == "__call")));
}
fbstring getCppSig() const;
fbstring getPrettyName() const {
if (className.empty()) {
return name;
if (isMethod()) {
return m_className + "::" + m_name;
} else {
return className + "::" + name;
return m_name;
}
}
fbstring getUniqueName() const {
if (className.empty()) {
return name;
if (isMethod()) {
return folly::to<fbstring>(m_className.length(), m_className,
'_', m_name);
} else {
return folly::to<fbstring>(className.length(), className, '_', name);
return m_name;
}
}
bool isReturnRef() const { return m_returnRef; }
DataType returnKindOf() const { return m_returnKindOf; }
fbstring returnCppType() const { return m_returnCppType; }
bool isIndirectReturn() const { return isKindOfIndirect(returnKindOf()); }
bool isCtor() const { return isMethod() && (m_name == "__construct"); }
bool isStatic() const { return m_flags & IsStatic; }
bool isVarArgs() const { return m_flags & VarArgsMask; }
bool usesThis() const { return isMethod() && !isStatic(); }
int numParams() const { return m_params.size(); }
int minNumParams() const { return m_minNumParams; }
int numTypeChecks() const { return m_numTypeChecks; }
const PhpParam& param(int p) const { return m_params[p]; }
const fbvector<PhpParam>& params() const { return m_params; }
private:
PhpFunc() = default;
void initComputedProps();
fbstring m_name;
fbstring m_className;
folly::dynamic m_func;
unsigned long m_flags;
// Return value
bool m_returnRef;
DataType m_returnKindOf;
fbstring m_returnCppType;
fbvector<PhpParam> m_params;
// Computed properties.
int m_minNumParams;
int m_numTypeChecks;
};
struct PhpClass {
fbstring name;
fbvector<fbstring> flags;
fbvector<PhpFunc> methods;
};
class PhpClass {
public:
explicit PhpClass(const folly::dynamic &c);
bool anyFlags(std::function<bool(const fbstring&)> pred,
const folly::dynamic& flagsArray);
fbstring name() const { return m_name; }
int numMethods() const { return m_methods.size(); }
const fbvector<PhpFunc>& methods() const { return m_methods; }
unsigned long flags() const { return m_flags; }
private:
folly::dynamic m_class;
fbstring m_name;
fbvector<PhpFunc> m_methods;
unsigned long m_flags;
void initFlagsProperty();
};
void parseIDL(const char* idlFilePath,
fbvector<PhpFunc>& funcVec,
fbvector<PhpClass>& classVec);
/////////////////////////////////////////////////////////////////////////////
}} // namespace HPHP::IDL
#endif