int IfBranchStatement::outputCPPIfBranch(CodeGenerator &cg, AnalysisResultPtr ar) { int varId = -1; if (m_condition) { if (m_condition->preOutputCPP(cg, ar, 0)) { cg.indentBegin("{\n"); varId = cg.createNewId(ar); m_condition->getType()->outputCPPDecl(cg, ar); cg.printf(" %s%d;\n", Option::TempPrefix, varId); m_condition->outputCPPBegin(cg, ar); cg.printf("%s%d = (", Option::TempPrefix, varId); m_condition->outputCPP(cg, ar); cg.printf(");\n"); m_condition->outputCPPEnd(cg, ar); } cg.printf("if ("); if (varId >= 0) { cg.printf("%s%d", Option::TempPrefix, varId); } else { m_condition->outputCPP(cg, ar); } cg.printf(") "); } if (m_stmt) { cg.indentBegin("{\n"); m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); } else { cg.printf("{}\n"); } return varId >= 0 ? 1 : 0; }
void WhileStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { int labelId = cg.createNewId(ar); cg.pushBreakScope(labelId); cg.indentBegin("{\n"); bool e_order = m_condition->preOutputCPP(cg, ar, 0); cg.printf("while ("); if (e_order) { cg.printf("true"); } else { m_condition->outputCPP(cg, ar); } cg.indentBegin(") {\n"); if (e_order) { m_condition->outputCPPBegin(cg, ar); cg.printf("if (!("); m_condition->outputCPP(cg, ar); cg.printf(")) break;\n"); m_condition->outputCPPEnd(cg, ar); } cg.printf("LOOP_COUNTER_CHECK(%d);\n", labelId); if (m_stmt) { m_stmt->outputCPP(cg, ar); } if (cg.findLabelId("continue", labelId)) { cg.printf("continue%d:;\n", labelId, labelId); } cg.indentEnd("}\n"); if (cg.findLabelId("break", labelId)) { cg.printf("break%d:;\n", labelId); } cg.indentEnd("}\n"); cg.popBreakScope(); }
void CatchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_valid) { cg.indentBegin("if (e.instanceof(\"%s\")) {\n", m_className.c_str()); VariableTablePtr variables = ar->getScope()->getVariables(); cg.printf("%s = e;\n", variables->getVariableName(ar, m_variable).c_str()); } else { cg.indentBegin("if (false) {\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}"); }
void FunctionScope::outputCPPCreateImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr scope = ar->getClassScope(); string clsNameStr = scope->getId(); const char *clsName = clsNameStr.c_str(); const char *consName = scope->classNameCtor() ? scope->getName().c_str() : "__construct"; cg.printf("%s%s *%s%s::create(", Option::ClassPrefix, clsName, Option::ClassPrefix, clsName); outputCPPParamsImpl(cg, ar); cg.indentBegin(") {\n"); cg.printf("CountableHelper h(this);\n"); cg.printf("init();\n"); cg.printf("%s%s(", Option::MethodPrefix, consName); outputCPPParamsCall(cg, ar, false); cg.printf(");\n"); cg.printf("return this;\n"); cg.indentEnd("}\n"); cg.indentBegin("ObjectData *%s%s::dynCreate(CArrRef params, " "bool construct /* = true */) {\n", Option::ClassPrefix, clsName); cg.printf("init();\n"); cg.indentBegin("if (construct) {\n"); cg.printf("CountableHelper h(this);\n"); OutputCPPDynamicInvokeCount(cg); outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix,consName, true, false, false, NULL, true); cg.indentEnd("}\n"); cg.printf("return this;\n"); cg.indentEnd("}\n"); if (isDynamic() || isSepExtension()) { cg.indentBegin("void %s%s::dynConstruct(CArrRef params) {\n", Option::ClassPrefix, clsName); OutputCPPDynamicInvokeCount(cg); outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix, consName, true, false, false, NULL, true); cg.indentEnd("}\n"); if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg.indentBegin("void %s%s::dynConstructFromEval(" "Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *caller) {\n", Option::ClassPrefix, clsName); outputCPPEvalInvoke(cg, ar, Option::MethodPrefix, consName, NULL, false); cg.indentEnd("}\n"); } } }
void StaticStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { BlockScopePtr scope = ar->getScope(); if (scope->inPseudoMain()) { if (m_exp->getCount() > 1) cg.indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { exp->outputCPP(cg, ar); cg.printf(";\n"); } else { ASSERT(false); } } if (m_exp->getCount() > 1) cg.indentEnd("}\n"); return; } VariableTablePtr variables = scope->getVariables(); if (m_exp->getCount() > 1) cg.indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr variable = assignment_exp->getVariable(); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); var->setContext(Expression::Declaration); const std::string &name = var->getName(); if (variables->needLocalCopy(name)) { cg.printf("%s%s = ref(%s%s);\n", Option::VariablePrefix, name.c_str(), Option::StaticVariablePrefix, name.c_str()); } cg.indentBegin("if (!%s%s%s) {\n", Option::InitPrefix, Option::StaticVariablePrefix, name.c_str()); exp->outputCPP(cg, ar); cg.printf(";\n"); cg.printf("%s%s%s = true;\n", Option::InitPrefix, Option::StaticVariablePrefix, name.c_str()); cg.indentEnd("}\n"); } else { ASSERT(false); } } if (m_exp->getCount() > 1) cg.indentEnd("}\n"); }
void GlobalStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_dynamicGlobal) { cg.printf("throw_fatal(\"dynamic global\");\n"); } else if (!ar->getScope()->inPseudoMain() || !isTopLevel()) { BlockScopePtr scope = ar->getScope(); if (m_exp->getCount() > 1) cg.indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); const string &name = var->getName(); VariableTablePtr variables = scope->getVariables(); if (variables->needLocalCopy(name)) { cg.printf("%s%s = ref(g->%s);\n", Option::VariablePrefix, name.c_str(), variables->getGlobalVariableName(ar, name).c_str()); } } else { // type inference should have set m_dynamicGlobal to true. ASSERT(false); } } if (m_exp->getCount() > 1) cg.indentEnd("}\n"); } }
void ClassStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (!classScope->isUserClass()) return; if (ar) ar->pushScope(classScope); switch (m_type) { case T_CLASS: break; case T_ABSTRACT: cg.printf("abstract "); break; case T_FINAL: cg.printf("final "); break; default: ASSERT(false); } cg.printf("class %s", m_name.c_str()); if (!m_parent.empty()) { cg.printf(" extends %s", m_parent.c_str()); } if (m_base) { cg.printf(" implements "); m_base->outputPHP(cg, ar); } cg.indentBegin(" {\n"); m_classScope.lock()->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg.indentEnd("}\n"); if (ar) ar->popScope(); }
void BlockStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_stmts) { cg.indentBegin("{\n"); m_stmts->outputCPP(cg, ar); cg.indentEnd("}\n"); } }
void EchoStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_exp->getCount() > 1) cg.indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { (*m_exp)[i]->outputCPPBegin(cg, ar); cg.printf("echo("); (*m_exp)[i]->outputCPP(cg, ar); cg.printf(");\n"); (*m_exp)[i]->outputCPPEnd(cg, ar); } if (m_exp->getCount() > 1) cg.indentEnd("}\n"); }
void MethodStatement::outputSwigFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); string fname = funcScope->getId(); string originalName = funcScope->getOriginalName(); int ac = funcScope->getMaxParamCount(); if (cg.getContext() == CodeGenerator::SwigFFIImpl) { printSource(cg); } cg.printf("Variant *%s(HphpSession *s", originalName.c_str()); ostringstream args; bool first = true; for (int i = 0; i < ac; i++) { cg.printf(", Variant *a%d", i); if (first) first = false; else args << ", "; args << "a" << i; } if (varArgs) { cg.printf(", Variant *va"); if (!first) args << ", "; args << "va"; } if (cg.getContext() == CodeGenerator::SwigFFIDecl) { cg.printf(");\n\n"); return; } cg.indentBegin(") {\n"); if (ret) { cg.printf("void *result;\n"); cg.printf("int kind = "); cg.printf("%s%s(&result", Option::FFIFnPrefix, fname.c_str()); if (ac > 0 || varArgs) cg.printf(", "); } else { cg.printf("%s%s(", Option::FFIFnPrefix, fname.c_str()); } cg.printf("%s);\n", args.str().c_str()); cg.printf("Variant *ret = "); if (ret) { cg.printf("hphpBuildVariant(kind, result);\n"); cg.printf("s->addVariant(ret);\n"); } else { cg.printf("hphpBuildVariant(0, 0);\n"); cg.printf("s->addVariant(ret);\n"); } cg.printf("return ret;\n"); cg.indentEnd("}\n\n"); }
void ClassStatement::outputJavaFFICPPCreator(CodeGenerator &cg, AnalysisResultPtr ar, FunctionScopePtr cons) { ClassScopePtr cls = m_classScope.lock(); string packageName = Option::JavaFFIRootPackage; int ac = cons ? cons->getMaxParamCount() : 0; bool varArgs = cons && cons->isVariableArgument(); const char *clsName = getOriginalName().c_str(); string mangledName = "Java_" + packageName + "_" + clsName + "_create"; Util::replaceAll(mangledName, ".", "_"); cg.printf("JNIEXPORT jlong JNICALL\n"); cg.printf("%s(JNIEnv *env, jclass cls", mangledName.c_str()); ostringstream args; bool first = true; if (varArgs) { args << ac << " + (((Variant *)va)->isNull() ? 0" << " : ((Variant *)va)->getArrayData()->size())"; first = false; } for (int i = 0; i < ac; i++) { if (first) first = false; else { args << ", "; } cg.printf(", jlong a%d", i); args << "*(Variant *)a" << i; } if (varArgs) { if (!first) { args << ", "; } cg.printf(", jlong va"); args << "((Variant *)va)->toArray()"; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl) { // java_stubs.h cg.printf(");\n\n"); return; } cg.indentBegin(") {\n"); cg.printf("ObjectData *obj = "); cg.printf("(NEW(%s%s)())->create(%s);\n", Option::ClassPrefix, cls->getId().c_str(), args.str().c_str()); cg.printf("obj->incRefCount();\n"); cg.printf("return (jlong)(NEW(Variant)(obj));\n"); cg.indentEnd("}\n\n"); }
void DoStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { cg.indentBegin("{\n"); int labelId = cg.createNewId(ar); cg.pushBreakScope(labelId); cg.indentBegin("do {\n"); cg.printf("LOOP_COUNTER_CHECK(%d);\n", labelId); if (m_stmt) { m_stmt->outputCPP(cg, ar); } if (cg.findLabelId("continue", labelId)) { cg.printf("continue%d:;\n", labelId); } cg.indentEnd("} while ("); m_condition->outputCPP(cg, ar); cg.printf(");\n"); if (cg.findLabelId("break", labelId)) { cg.printf("break%d:;\n", labelId); } cg.indentEnd("}\n"); cg.popBreakScope(); }
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) { ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp); int count = exps->getCount(); if (count > 1) { bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0); bool inExpression = ar->inExpression(); ar->setInExpression(false); bool fix_en = false; for (int i = 1; i < count; i++) { if ((*exps)[i]->preOutputCPP(cg, ar, 0)) { fix_en = true; break; } } ar->setInExpression(inExpression); if (inExpression && fix_en) { ar->wrapExpressionBegin(cg); std::string tmp = genCPPTemp(cg, ar); cg.printf("bool %s = (", tmp.c_str()); (*exps)[0]->outputCPPExistTest(cg, ar, m_op); cg.printf(");\n"); for (int i = 1; i < count; i++) { cg.indentBegin("if (%s) {\n", tmp.c_str()); ExpressionPtr e = (*exps)[i]; e->preOutputCPP(cg, ar, 0); cg.printf("%s = (", tmp.c_str()); e->outputCPPExistTest(cg, ar, m_op); cg.printf(");\n"); } for (int i = 1; i < count; i++) { cg.indentEnd("}\n"); } m_cppTemp = tmp; } else if (state & FixOrder) { preOutputStash(cg, ar, state); fix_e1 = true; } return fix_e1 || fix_en; } } return Expression::preOutputCPP(cg, ar, state); }
void ClassStatement::outputJavaFFIConstructor(CodeGenerator &cg, AnalysisResultPtr ar, FunctionScopePtr cons) { int ac = cons ? cons->getMaxParamCount() : 0; bool varArgs = cons && cons->isVariableArgument(); // generates the constructor cg.printf("public %s(", getOriginalName().c_str()); ostringstream args; ostringstream params; bool first = true; for (int i = 0; i < ac; i++) { if (first) { first = false; } else { cg.printf(", "); args << ", "; params << ", "; } cg.printf("HphpVariant a%d", i); args << "a" << i << ".getVariantPtr()"; params << "long a" << i; } if (varArgs) { if (!first) { cg.printf(", "); args << ", "; params << ", "; } cg.printf("HphpVariant va"); args << "va.getVariantPtr()"; params << "long va"; } cg.indentBegin(") {\n"); cg.printf("this(create(%s));\n", args.str().c_str()); cg.indentEnd("}\n\n"); // generates the native method stub for creating the object cg.printf("private static native long create(%s);\n\n", params.str().c_str()); }
void MethodStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar) ar->pushScope(funcScope); m_modifiers->outputPHP(cg, ar); cg.printf(" function "); if (m_ref) cg.printf("&"); cg.printf("%s(", m_originalName.c_str()); if (m_params) m_params->outputPHP(cg, ar); if (m_stmt) { cg.indentBegin(") {\n"); funcScope->outputPHP(cg, ar); m_stmt->outputPHP(cg, ar); cg.indentEnd("}\n"); } else { cg.printf(");\n"); } if (ar) ar->popScope(); }
void InterfaceStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getOutput() == CodeGenerator::InlinedPHP || cg.getOutput() == CodeGenerator::TrimmedPHP) { if (!classScope->isUserClass()) { return; } } if (ar) ar->pushScope(classScope); cg.printf("interface %s", m_name.c_str()); if (m_base) { cg.printf(" extends "); m_base->outputPHP(cg, ar); } cg.indentBegin(" {\n"); m_classScope.lock()->outputPHP(cg, ar); if (m_stmt) m_stmt->outputPHP(cg, ar); cg.indentEnd("}\n"); if (ar) ar->popScope(); }
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg.printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, m_name.c_str(), Option::ClassStaticsPrefix, classScope->getId().c_str()); } if (classScope->isVolatile()) { cg.printf("g->CDEC(%s) = true;\n", m_name.c_str()); } const vector<string> &bases = classScope->getBases(); for (vector<string>::const_iterator it = bases.begin(); it != bases.end(); ++it) { ClassScopePtr base = ar->findClass(*it); if (base && base->isVolatile()) { cg.printf("checkClassExists(\"%s\", g);\n", base->getOriginalName()); } } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg.printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { bool system = cg.getOutput() == CodeGenerator::SystemCPP; ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); cg.printf("class %s%s", Option::ClassPrefix, clsName); if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)) { if (!parCls || parCls->isRedeclaring()) { cg.printf(" : public DynamicObjectData"); } else { cg.printf(" : public %s%s", Option::ClassPrefix, parCls->getId().c_str()); } } else { if (classScope->derivesFromRedeclaring()) { cg.printf(" : public DynamicObjectData"); } else if (system) { cg.printf(" : public ExtObjectData"); } else { cg.printf(" : public ObjectData"); } } cg.indentBegin(" {\n"); if (Option::GenerateCPPMacros) { // Get all of this class's ancestors vector<string> bases; getAllParents(ar, bases); // Eliminate duplicates sort(bases.begin(), bases.end()); bases.erase(unique(bases.begin(), bases.end()), bases.end()); cg.indentBegin("BEGIN_CLASS_MAP(%s)\n", Util::toLower(classScope->getName()).c_str()); for (unsigned int i = 0; i < bases.size(); i++) { cg.printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } cg.indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = (!parCls && !m_parent.empty()) || classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(), m_parent.empty() ? "ObjectData" : m_parent.c_str()); } else { cg.printf("DECLARE_DYNAMIC_CLASS(%s, %s)\n", clsName, m_originalName.c_str()); } if (system || Option::EnableEval >= Option::LimitedEval) { cg.printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg.printf("DECLARE_ROOT;\n"); if (!dyn && !idyn) { cg.printf("private: ObjectData* root;\n"); cg.printf("public:\n"); cg.printf("virtual ObjectData *getRoot() { return root; }\n"); } } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId() + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg.printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg.printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg.printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } classScope->getVariables()->outputCPPPropertyDecl(cg, ar, classScope->derivesFromRedeclaring()); if (!classScope->getAttribute(ClassScope::HasConstructor)) { FunctionScopePtr func = classScope->findFunction(ar, "__construct", false); if (func && !func->isAbstract() && !classScope->isInterface()) { ar->pushScope(func); func->outputCPPCreateDecl(cg, ar); ar->popScope(); } } if (classScope->getAttribute(ClassScope::HasDestructor)) { cg.printf("public: virtual void destruct();\n"); } // doCall if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) { cg.printf("Variant doCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } // doGet if (classScope->getAttribute(ClassScope::HasUnknownPropHandler)) { cg.printf("Variant doGet(Variant v_name, bool error);\n"); } if (classScope->isRedeclaring() && !classScope->derivesFromRedeclaring()) { cg.printf("Variant doRootCall(Variant v_name, Variant v_arguments, " "bool fatal);\n"); } if (m_stmt) m_stmt->outputCPP(cg, ar); { set<string> done; classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName); } if (cg.getOutput() == CodeGenerator::SystemCPP && ar->isBaseSysRsrcClass(clsName) && !classScope->hasProperty("rsrc")) { cg.printf("public: Variant %srsrc;\n", Option::PropertyPrefix); } cg.indentEnd("};\n"); if (redeclared) { cg.indentBegin("class %s%s : public ClassStatics {\n", Option::ClassStaticsPrefix, clsName); cg.printf("public:\n"); cg.printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); cg.printf("%s%s() : ClassStatics(%d) {}\n", Option::ClassStaticsPrefix, clsName, classScope->getRedeclaringId()); cg.indentBegin("Variant %sgetInit(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sgetInit(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke(const char *c, const char *s, " "CArrRef params, int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Object create(CArrRef params, bool init = true, " "ObjectData* root = NULL) {\n"); cg.printf("return Object((NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::ClassPrefix, clsName); cg.indentEnd("}\n"); cg.indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentEnd("};\n"); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg.printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg.indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg.printf("parent->init();\n"); } else { cg.printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } if (classScope->getVariables()-> getAttribute(VariableTable::NeedGlobalPointer)) { cg.printDeclareGlobals(); } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg.indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg.printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg.indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg.indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg.indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.printf("return g;\n"); cg.indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent) && parCls && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isVolatile()) { cg.printf("g->CDEC(%s) = true;\n", m_name.c_str()); } return; } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s);\n", clsName); } break; case CodeGenerator::CppDeclaration: { printSource(cg); cg.printf("class %s%s", Option::ClassPrefix, clsName); cg.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("};\n"); } break; case CodeGenerator::CppImplementation: // do nothing break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: // do nothing break; case CodeGenerator::JavaFFI: { // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFIInterface); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); cgCls.printf("public interface %s", getOriginalName().c_str()); if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" extends "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: // do nothing break; default: ASSERT(false); break; } ar->popScope(); }
void CatchStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) { cg.printf(" catch (%s $%s) ", m_className.c_str(), m_variable.c_str()); cg.indentBegin("{\n"); if (m_stmt) m_stmt->outputPHP(cg, ar); cg.indentEnd("}"); }
/** * Generates the Java stub method for a PHP toplevel function. * * @author qixin */ void MethodStatement::outputJavaFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); string fname = funcScope->getId(); string originalName = funcScope->getOriginalName(); if (originalName.length() < fname.length()) { // if there are functions of the same name, fname may contain "$$..." // in the end originalName += fname.substr(originalName.length()); } if (originalName == "clone" || originalName == "equals" || originalName == "finalize" || originalName == "getClass" || originalName == "hashCode" || originalName == "notify" || originalName == "notifyAll" || originalName == "toString" || originalName == "wait") { // not to clash with Java method names originalName = "_" + originalName; } if (cg.getContext() == CodeGenerator::JavaFFIInterface || inClass && m_modifiers->isAbstract()) { // skip all the abstract methods, because php overriding is not very // compatible with Java return; } if (!inClass) printSource(cg); // This Java method extracts the Variant pointer from the HphpVariant // argument as a 64-bit integer, and then calls the native version. bool exposeNative = false; int ac = funcScope->getMaxParamCount(); if (ac > 0 || varArgs || !isStatic || !ret && inClass || cg.getContext() == CodeGenerator::JavaFFIInterface) { // make methods always return something, so that they can override // each other cg.printf("public %s%s %s(", (isStatic ? "static " : ""), (!ret && !inClass ? "void" : "HphpVariant"), originalName.c_str()); ostringstream args; bool first = true; if (!isStatic) { // instance method has an additional parameter args << "this.getVariantPtr()"; } for (int i = 0; i < ac; i++) { if (first) { first = false; if (!isStatic) args << ", "; } else { cg.printf(", "); args << ", "; } cg.printf("HphpVariant a%d", i); args << "a" << i << ".getVariantPtr()"; } if (varArgs) { if (!first) { cg.printf(", "); args << ", "; } else if (!isStatic) { args << ", "; } cg.printf("HphpVariant va"); args << "va.getVariantPtr()"; } if (cg.getContext() == CodeGenerator::JavaFFIInterface) { cg.printf(");\n\n"); return; } cg.indentBegin(") {\n"); cg.printf("%s%s_native(%s);\n", (ret ? "return " : ""), originalName.c_str(), args.str().c_str()); if (!ret && inClass) { cg.printf("return HphpNull.phpNull();\n"); } cg.indentEnd("}\n\n"); } else { exposeNative = true; } // the native method stub cg.printf("%s %snative %s %s%s(", (exposeNative ? "public" : "private"), (isStatic ? "static " : ""), (ret ? "HphpVariant" : "void"), originalName.c_str(), (exposeNative ? "" : "_native")); bool first = true; if (!isStatic) { // instance method has an additional parameter cg.printf("long targetPtr"); first = false; } for (int i = 0; i < ac; i++) { if (first) first = false; else cg.printf(", "); cg.printf("long a%d", i); } if (varArgs) { if (!first) cg.printf(", "); cg.printf("long va"); } cg.printf(");\n\n"); }
void MethodStatement::outputHSFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { if (!m_className.empty()) { // Haskell currently doesn't support FFI for class methods. return; } FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); string fname = funcScope->getId().c_str(); cg.indentBegin("foreign import ccall \"stubs.h %s%s\" %s%s\n", Option::FFIFnPrefix, fname.c_str(), Option::FFIFnPrefix, fname.c_str()); cg.printf(":: "); if (ret) { cg.printf("PtrPtr a -> "); } int ac = funcScope->getMaxParamCount(); for (int i = 0; i < ac; ++i) { cg.printf("HphpVariantPtr -> "); } if (varArgs) { cg.printf("HphpVariantPtr -> "); } if (ret) { cg.printf("IO CInt"); } else { cg.printf("IO ()"); } cg.indentEnd("\n"); cg.printf("f_%s :: ", fname.c_str()); bool first = true; if (ac > 0) { cg.printf("("); } for (int i = 0; i < ac; ++i) { if (first) { first = false; } else { cg.printf(", "); } cg.printf("VariantAble a%d", i); } if (ac > 0) { cg.printf(") => "); } for (int i = 0; i < ac; ++i) { cg.printf("a%d -> ", i); } if (varArgs) { cg.printf("[Variant] -> "); } if (ret) { cg.printf("IO Variant"); } else { cg.printf("IO ()"); } cg.printf("\n"); cg.printf("f_%s ", fname.c_str()); for (int i = 0; i < ac; ++i) { cg.printf("v%d ", i); } if (varArgs) { cg.printf("va "); } cg.indentBegin("=%s\n", ret ? " alloca (\\pres ->" : ""); for (int i = 0; i < ac; ++i) { cg.indentBegin("withExportedVariant (toVariant v%d) (\\p%d ->\n", i, i); } if (varArgs) { cg.indentBegin("withVParamList va (\\pva ->\n"); } cg.indentBegin("do\n"); cg.printf("%sffi_%s", ret ? "t <- " : "", fname.c_str()); if (ret) { cg.printf(" pres"); } for (int i = 0; i < ac; ++i) { cg.printf(" p%d", i); } if (varArgs) { cg.printf(" pva"); } if (ret) { cg.printf("\n"); cg.printf("ppres <- peek pres\n"); cg.printf("buildVariant (fromIntegral t) ppres"); } cg.indentEnd(""); // end do if (varArgs) { cg.indentEnd(")"); // end varargs } for (int i = 0; i < ac; ++i) { cg.indentEnd(")"); // end wEV i } if (ret) { cg.indentEnd(")"); // end alloca } else { cg.indentEnd(""); } cg.printf("\n"); return; }
void MethodStatement::outputCPPFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); string fname = funcScope->getId(); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); if (inClass && m_modifiers->isAbstract()) { return; } if (fname == "__lval" || fname == "__offsetget_lval") { return; } if (ret) { cg.printf("int"); } else { cg.printf("void"); } cg.printf(" %s%s%s(", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); if (ret) { cg.printf("void** res"); } bool first = !ret; if (!isStatic) { // instance methods need one additional parameter for the target if (first) { first = false; } else { cg.printf(", "); } cg.printf("Variant *target"); } int ac = funcScope->getMaxParamCount(); for (int i = 0; i < ac; ++i) { if (first) { first = false; } else { cg.printf(", "); } cg.printf("Variant *a%d", i); } if (varArgs) { if (!first) { cg.printf(", "); } cg.printf("Variant *va"); } cg.printf(")"); if (cg.getContext() == CodeGenerator::CppFFIDecl) { cg.printf(";\n"); } else { cg.indentBegin(" {\n"); if (ret) { cg.printf("return hphp_ffi_exportVariant("); } if (!inClass) { // simple function call cg.printf("%s%s(", Option::FunctionPrefix, fname.c_str()); } else if (isStatic) { // static method call cg.printf("%s%s::%s%s(", Option::ClassPrefix, m_className.c_str(), Option::MethodPrefix, fname.c_str()); } else { // instance method call cg.printf("dynamic_cast<%s%s *>(target->getObjectData())->", Option::ClassPrefix, m_className.c_str()); cg.printf("%s%s(", Option::MethodPrefix, fname.c_str()); } first = true; if (varArgs) { cg.printf("%d + (va->isNull() ? 0 : va->getArrayData()->size())", ac); first = false; } for (int i = 0; i < ac; ++i) { if (first) { first = false; } else { cg.printf(", "); } cg.printf("*a%d", i); } if (varArgs) { cg.printf(", va->toArray()"); } if (ret) { cg.printf("), res"); } cg.printf(");\n"); cg.indentEnd("} /* function */\n"); } return; }
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr scope = ar->getClassScope(); string origFuncName; ar->pushScope(funcScope); if (outputFFI(cg, ar)) return; cg.setPHPLineNo(-1); if (cg.getContext() == CodeGenerator::CppImplementation) { printSource(cg); } switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { if (!m_stmt) { cg.printf("// "); } m_modifiers->outputCPP(cg, ar); if (m_name == "__offsetget_lval") { cg.printf("virtual "); } TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } if (m_name == "__lval") { cg.printf(" &___lval("); } else if (m_name == "__offsetget_lval") { cg.printf(" &___offsetget_lval("); } else if (m_modifiers->isStatic() && m_stmt) { // Static method wrappers get generated as support methods cg.printf(" %s%s(const char* cls%s", Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, true); if (m_stmt) { cg.printf(");\n"); } else { cg.printf(") = 0;\n"); } if (funcScope->isConstructor(scope) && !funcScope->isAbstract() && !scope->isInterface()) { funcScope->outputCPPCreateDecl(cg, ar); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } origFuncName = std::string(scope->getOriginalName()) + "::" + m_originalName; if (Option::HotFunctions.find(origFuncName) != Option::HotFunctions.end()) { cg.printf(" __attribute((__section__(\".text.hot\")))"); } else if (Option::ColdFunctions.find(origFuncName) != Option::ColdFunctions.end()) { cg.printf(" __attribute((__section__(\".text.cold\")))"); } if (m_name == "__lval") { cg.printf(" &%s%s::___lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_name == "__offsetget_lval") { cg.printf(" &%s%s::___offsetget_lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_modifiers->isStatic()) { cg.printf(" %s%s::%s%s(const char* cls%s", Option::ClassPrefix, scope->getId().c_str(), Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId().c_str(), Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg.indentBegin(") {\n"); if (m_modifiers->isStatic()) { cg.printf("STATIC_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } else { cg.printf("INSTANCE_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } if (Option::GenRTTIProfileData && m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasRTTI()) { const string ¶mName = param->getName(); int id = ar->getParamRTTIEntryId(ar->getClassScope(), funcScope, paramName); if (id != -1) { cg.printf("RTTI_INJECTION(%s%s, %d);\n", Option::VariablePrefix, paramName.c_str(), id); } } } } if (m_name == "__lval" || m_name == "__offsetget_lval") { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("Variant &v = %s->__lvalProxy;\n", cg.getOutput() == CodeGenerator::SystemCPP ? "get_system_globals()" : "get_global_variables()"); string lowered = Util::toLower(m_originalName); cg.printf("v = %s%s(%s%s);\n", Option::MethodPrefix, lowered.c_str(), Option::VariablePrefix, param->getName().c_str()); cg.printf("return v;\n"); } else { if (funcScope->isConstructor(scope)) { cg.printf("bool oldInCtor = gasInCtor(true);\n"); } else if (m_name == "__destruct") { cg.printf("setInDtor();\n"); } else if (m_name == "__call") { ParameterExpressionPtr param; if (m_params->getCount() > 0) { param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("INCALL_HELPER(%s%s);\n", Option::VariablePrefix, param->getName().c_str()); } else { cg.printf("INCALL_HELPER(\"\");\n"); } } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes if (!funcScope->isStatic() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { cg.printf("%sthis = this;\n", Option::VariablePrefix); } outputCPPStmt(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } cg.indentEnd("} /* function */\n"); } break; default: break; } ar->popScope(); }
void FunctionScope::outputCPPEvalInvoke(CodeGenerator &cg, AnalysisResultPtr ar, const char *funcPrefix, const char *name, const char *extraArg /* = NULL */, bool ret /* = true */, bool constructor /* = false */) { const char *voidWrapper = m_returnType ? "" : ", null"; const char *retrn = ret ? "return " : ""; int maxParam = m_maxParam; bool variable = isVariableArgument(); stringstream callss; callss << retrn << ((ret && m_refReturn) ? "ref(" : "(") << funcPrefix << name << "("; if (extraArg) { callss << extraArg; if (variable) { callss << ","; } } if (variable) { callss << "count"; } bool preArgs = variable || extraArg; // Build temps for (int i = 0; i < m_maxParam; i++) { cg.printf("Variant a%d;\n", i); } cg.printf("const std::vector<Eval::ExpressionPtr> ¶ms = " "caller->params();\n"); FunctionScope::OutputCPPDynamicInvokeCount(cg); outputCPPInvokeArgCountCheck(cg, ar, ret, constructor); cg.printf("std::vector<Eval::ExpressionPtr>::const_iterator it = " "params.begin();\n"); cg.indentBegin("do {\n"); for (int i = 0; i < m_maxParam; i++) { cg.printf("if (it == params.end()) break;\n"); if (i < m_minParam && (preArgs || i > 0)) { callss << ", "; } if (isRefParam(i)) { if (i < m_minParam) callss << "ref(a" << i << ")"; cg.printf("a%d = ref((*it)->refval(env));\n", i); } else { if (i < m_minParam) callss << "a" << i; cg.printf("a%d = (*it)->eval(env);\n", i); } cg.printf("it++;\n"); } cg.indentEnd("} while(false);\n"); // Put extra args into vargs or just eval them if (variable) { cg.printf("Array vargs;\n"); } cg.indentBegin("for (; it != params.end(); ++it) {\n"); const char *paramEval = "(*it)->eval(env)"; if (isReferenceVariableArgument()) { paramEval = "ref((*it)->refval(env, false))"; } if (variable) cg.printf("vargs.append("); cg.printf(paramEval); if (variable) cg.printf(")"); cg.printf(";\n"); cg.indentEnd("}\n"); if (variable || getOptionalParamCount()) { cg.printf("if (count <= %d) ", m_minParam); } // No optional args string call = callss.str(); cg.printf("%s", call.c_str()); cg.printf(")%s);\n", voidWrapper); // Optional args for (int iMax = m_minParam + 1; iMax <= maxParam; iMax++) { cg.printf("else "); if (iMax < maxParam || variable) { cg.printf("if (count == %d) ", iMax); } cg.printf("%s", call.c_str()); for (int i = m_minParam; i < iMax; i++) { if (i > 0 || preArgs) cg.printf(", "); if (isRefParam(i)) { cg.printf("ref(a%d)", i); } else { cg.printf("a%d", i); } } cg.printf(")%s);\n", voidWrapper); } // Var args if (variable) { cg.printf("%s,", call.c_str()); for (int i = m_minParam; i < maxParam; i++) { if (isRefParam(i)) { cg.printf("ref(a%d), ", i); } else { cg.printf("a%d, ", i); } } cg.printf("vargs)%s);\n", voidWrapper); } }
void MethodStatement::outputJavaFFICPPStub(CodeGenerator &cg, AnalysisResultPtr ar) { // TODO translate PHP namespace once that is supported string packageName = Option::JavaFFIRootPackage; FunctionScopePtr funcScope = m_funcScope.lock(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); string fname = funcScope->getId(); int ac = funcScope->getMaxParamCount(); bool exposeNative = !(ac > 0 || varArgs || !isStatic || !ret && inClass); if (inClass && m_modifiers->isAbstract()) { // skip all the abstract methods, because hphp doesn't generate code // for them return; } if (fname == "__lval" || fname == "__offsetget_lval") return; const char *clsName; if (inClass) { // uses capitalized original class name ClassScopePtr cls = ar->findClass(m_className); clsName = cls->getOriginalName(); } else { clsName = "HphpMain"; } string mangledName = "Java." + packageName + "." + clsName + "." + fname + (exposeNative ? "" : "_native"); // all the existing "_" are replaced as "_1" Util::replaceAll(mangledName, "_", "_1"); Util::replaceAll(mangledName, ".", "_"); cg.printf("JNIEXPORT %s JNICALL\n", ret ? "jobject" : "void"); cg.printf("%s(JNIEnv *env, %s target", mangledName.c_str(), (isStatic ? "jclass" : "jobject")); ostringstream args; bool first = true; if (!isStatic) { // instance method also gets an additional argument, which is a Variant // pointer to the target, encoded in int64 first = false; cg.printf(", jlong targetPtr"); args << "(Variant *)targetPtr"; } for (int i = 0; i < ac; i++) { cg.printf(", jlong a%d", i); if (first) first = false; else args << ", "; args << "(Variant *)a" << i; } if (varArgs) { cg.printf(", jlong va"); if (!first) args << ", "; args << "(Variant *)va"; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl) { // java_stubs.h cg.printf(");\n\n"); return; } cg.indentBegin(") {\n"); // support static/instance methods if (ret) { cg.printf("void *result;\n"); cg.printf("int kind = "); cg.printf("%s%s%s(&result", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); if (!isStatic || ac > 0 || varArgs) cg.printf(", "); } else { cg.printf("%s%s%s(", Option::FFIFnPrefix, (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str()); } cg.printf("%s);\n", args.str().c_str()); if (ret) { if (!inClass) { // HphpMain extends hphp.Hphp. cg.printf("jclass hphp = env->GetSuperclass(target);\n"); } else { cg.printf("jclass hphp = env->FindClass(\"hphp/Hphp\");\n"); } cg.printf("return exportVariantToJava(env, hphp, result, kind);\n"); } cg.indentEnd("} /* function */\n\n"); }
void ForEachStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { cg.indentBegin("{\n"); int labelId = cg.createNewId(ar); cg.pushBreakScope(labelId); int mapId = cg.createNewId(ar); bool passTemp; bool isArray = false; if (m_ref) { passTemp = true; cg.printf("Variant %s%d = ref(", Option::MapPrefix, mapId); m_array->outputCPPImpl(cg, ar); cg.printf(");\n"); cg.printf("%s%d.escalate();\n", Option::MapPrefix, mapId); } else if (!m_array->is(Expression::KindOfSimpleVariable) || m_array->isThis()) { passTemp = true; cg.printf("Variant %s%d = ", Option::MapPrefix, mapId); TypePtr expectedType = m_array->getExpectedType(); // Clear m_expectedType to avoid type cast (toArray). m_array->setExpectedType(TypePtr()); m_array->outputCPP(cg, ar); m_array->setExpectedType(expectedType); cg.printf(";\n"); } else { passTemp = false; } int iterId = cg.createNewId(ar); cg.printf("for ("); if (m_ref) { cg.printf("MutableArrayIterPtr %s%d = %s%d.begin(", Option::IterPrefix, iterId, Option::MapPrefix, mapId); if (m_name) { cg.printf("&"); m_name->outputCPP(cg, ar); } else { cg.printf("NULL"); } cg.printf(", "); m_value->outputCPP(cg, ar); cg.printf("); %s%d->advance();", Option::IterPrefix, iterId); } else { if (passTemp) { cg.printf("ArrayIterPtr %s%d = %s%d.begin(", Option::IterPrefix, iterId, Option::MapPrefix, mapId); ClassScopePtr cls = ar->getClassScope(); if (cls) { cg.printf("\"%s\"", cls->getName().c_str()); } cg.printf("); "); cg.printf("!%s%d->end(); %s%d->next()", Option::IterPrefix, iterId, Option::IterPrefix, iterId); } else { TypePtr actualType = m_array->getActualType(); if (actualType && actualType->is(Type::KindOfArray)) { isArray = true; cg.printf("ArrayIter %s%d = ", Option::IterPrefix, iterId); } else { cg.printf("ArrayIterPtr %s%d = ", Option::IterPrefix, iterId); } TypePtr expectedType = m_array->getExpectedType(); // Clear m_expectedType to avoid type cast (toArray). m_array->setExpectedType(TypePtr()); m_array->outputCPP(cg, ar); m_array->setExpectedType(expectedType); cg.printf(".begin("); ClassScopePtr cls = ar->getClassScope(); if (cls) { cg.printf("\"%s\"", cls->getName().c_str()); } cg.printf("); "); if (isArray) { cg.printf("!%s%d.end(); ", Option::IterPrefix, iterId); cg.printf("++%s%d", Option::IterPrefix, iterId); } else { cg.printf("!%s%d->end(); ", Option::IterPrefix, iterId); cg.printf("%s%d->next()", Option::IterPrefix, iterId); } } } cg.indentBegin(") {\n"); cg.printf("LOOP_COUNTER_CHECK(%d);\n", labelId); if (!m_ref) { m_value->outputCPP(cg, ar); cg.printf(isArray ? " = %s%d.second();\n" : " = %s%d->second();\n", Option::IterPrefix, iterId); if (m_name) { m_name->outputCPP(cg, ar); cg.printf(isArray ? " = %s%d.first();\n" : " = %s%d->first();\n", Option::IterPrefix, iterId); } } if (m_stmt) { m_stmt->outputCPP(cg, ar); } if (cg.findLabelId("continue", labelId)) { cg.printf("continue%d:;\n", labelId); } cg.indentEnd("}\n"); if (cg.findLabelId("break", labelId)) { cg.printf("break%d:;\n", labelId); } cg.popBreakScope(); cg.indentEnd("}\n"); }