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");
}
Exemple #12
0
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 &paramName = 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> &params = "
            "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");
}