void SimpleFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  outputLineMap(cg, ar);

  if (!m_className.empty()) {
    cg.printf("%s::%s(", m_className.c_str(), m_name.c_str());
  } else {

    if (cg.getOutput() == CodeGenerator::InlinedPHP ||
        cg.getOutput() == CodeGenerator::TrimmedPHP) {

      if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
          cg.usingStream(CodeGenerator::PrimaryStream) &&
          Option::DynamicFunctionCalls.find(m_name) !=
          Option::DynamicFunctionCalls.end()) {
        int funcNamePos = Option::DynamicFunctionCalls[m_name];
        if (m_params && m_params->getCount() &&
            m_params->getCount() >= funcNamePos + 1) {
          if (funcNamePos == -1) funcNamePos = m_params->getCount() - 1;
          ExpressionPtr funcName = (*m_params)[funcNamePos];
          if (!funcName->is(Expression::KindOfScalarExpression)) {

            cg.printf("%s(", m_name.c_str());
            for (int i = 0; i < m_params->getCount(); i++) {
              if (i > 0) cg.printf(", ");
              if (i == funcNamePos) {
                cg.printf("%sdynamic_load(", Option::IdPrefix.c_str());
                funcName->outputPHP(cg, ar);
                cg.printf(")");
              } else {
                ExpressionPtr param = (*m_params)[i];
                if (param) param->outputPHP(cg, ar);
              }
            }
            cg.printf(")");
            return;
          }
        }
      }
      /* simptodo: I dunno
      if (m_type == RenderTemplateFunction && !m_template.empty()) {
        cg.printf("%s_%s(", m_name.c_str(),
                  Util::getIdentifier(m_template).c_str());
      } else if (m_type == RenderTemplateIncludeFunction) {
        string templateName = ar->getProgram()->getCurrentTemplate();
        cg.printf("%s_%s(", m_name.c_str(),
                  Util::getIdentifier(templateName).c_str());
      } else {
      */
        cg.printf("%s(", m_name.c_str());
        //}

    } else {
      cg.printf("%s(", m_name.c_str());
    }
  }

  if (m_params) m_params->outputPHP(cg, ar);
  cg.printf(")");
}
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg,
                                          AnalysisResultPtr ar,
                                          bool isVector,
                                          bool pre) {
  ASSERT(pre == !m_cppTemp.empty());
  if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) {
    return false;
  }
  if (hasNonArrayCreateValue()) return false;

  unsigned int n = isVector ? m_exps.size() : 0;
  bool uniqLitstrKeys = false;
  if (isVector) {
    n = m_exps.size();
  } else {
    n = checkLitstrKeys();
    if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true;
  }
  if (isVector) {
    if (ar->m_arrayIntegerKeyMaxSize < (int)n) ar->m_arrayIntegerKeyMaxSize = n;
  } else if (uniqLitstrKeys) {
    if (ar->m_arrayLitstrKeyMaxSize < (int)n) ar->m_arrayLitstrKeyMaxSize = n;
  } else {
    return false;
  }
  if (pre) {
    Expression::preOutputCPP(cg, ar, StashKidVars);
    cg_printf("ArrayInit %s(", m_cppTemp.c_str());
    outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
    cg_printf(");\n");
  } else {
    outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
  }
  return true;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  outputLineMap(cg, ar);

  if (m_class || !m_className.empty()) {
    StaticClassName::outputPHP(cg, ar);
    cg_printf("::");
    m_nameExp->outputPHP(cg, ar);
  } else {
    const char *prefix = Option::IdPrefix.c_str();
    if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
        cg.usingStream(CodeGenerator::PrimaryStream) &&
        !m_nameExp->is(Expression::KindOfScalarExpression)) {
      cg_printf("${%sdynamic_load($%stmp = (", prefix, prefix);
      m_nameExp->outputPHP(cg, ar);
      cg_printf("), '%stmp'", prefix);
      cg_printf(")}");
    } else {
      m_nameExp->outputPHP(cg, ar);
    }
  }

  cg_printf("(");
  if (m_params) m_params->outputPHP(cg, ar);
  cg_printf(")");
}
Example #4
0
void FunctionScope::outputCPPArguments(ExpressionListPtr params,
                                       CodeGenerator &cg,
                                       AnalysisResultPtr ar, int extraArg,
                                       bool variableArgument,
                                       int extraArgArrayId /* = -1 */) {
  int paramCount = params ? params->getOutputCount() : 0;
  ASSERT(extraArg <= paramCount);
  int iMax = paramCount - extraArg;
  bool extra = false;

  if (variableArgument) {
    if (paramCount == 0) {
      cg.printf("0");
    } else {
      cg.printf("%d, ", paramCount);
    }
  }
  int firstExtra = 0;
  for (int i = 0; i < paramCount; i++) {
    ExpressionPtr param = (*params)[i];
    cg.setItemIndex(i);
    if (i > 0) cg.printf(extra ? "." : ", ");
    if (!extra && (i == iMax || extraArg < 0)) {
      if (extraArgArrayId != -1) {
        if (cg.getOutput() == CodeGenerator::SystemCPP) {
          cg.printf("SystemScalarArrays::%s[%d]",
                    Option::SystemScalarArrayName, extraArgArrayId);
        } else {
          cg.printf("ScalarArrays::%s[%d]",
                    Option::ScalarArrayName, extraArgArrayId);
        }
        break;
      }
      extra = true;
      // Parameter arrays are always vectors.
      cg.printf("Array(ArrayInit(%d, true).", paramCount - i);
      firstExtra = i;
    }
    if (extra) {
      bool needRef = param->hasContext(Expression::RefValue) &&
                     !param->hasContext(Expression::NoRefWrapper) &&
                     param->isRefable();
      cg.printf("set%s(%d, ", needRef ? "Ref" : "", i - firstExtra);
      if (needRef) {
        // The parameter itself shouldn't be wrapped with ref() any more.
        param->setContext(Expression::NoRefWrapper);
      }
      param->outputCPP(cg, ar);
      cg.printf(")");
    } else {
      param->outputCPP(cg, ar);
    }
  }
  if (extra) {
    cg.printf(".create())");
  }
}
Example #5
0
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
  bool decl = true;
  if (cg.getContext() == CodeGenerator::CppConstantsDecl) {
    decl = false;
  }

  bool printed = false;
  for (StringToSymbolMap::iterator iter = m_symbolMap.begin(),
         end = m_symbolMap.end(); iter != end; ++iter) {
    Symbol *sym = &iter->second;
    if (!sym->declarationSet() || sym->isDynamic()) continue;
    if (sym->isSystem() && cg.getOutput() != CodeGenerator::SystemCPP) continue;
    const string &name = sym->getName();
    ConstructPtr value = sym->getValue();
    printed = true;

    cg_printf(decl ? "extern const " : "const ");
    TypePtr type = sym->getFinalType();
    bool isString = type->is(Type::KindOfString);
    if (isString) {
      cg_printf("StaticString");
    } else {
      type->outputCPPDecl(cg, ar);
    }
    if (decl) {
      cg_printf(" %s%s", Option::ConstantPrefix,
                cg.formatLabel(name).c_str());
    } else {
      cg_printf(" %s%s", Option::ConstantPrefix,
                cg.formatLabel(name).c_str());
      cg_printf(isString ? "(" : " = ");
      if (value) {
        ExpressionPtr exp = dynamic_pointer_cast<Expression>(value);
        ASSERT(!exp->getExpectedType());
        ScalarExpressionPtr scalarExp =
          dynamic_pointer_cast<ScalarExpression>(exp);
        if (isString && scalarExp) {
          cg_printf("LITSTR_INIT(%s)",
                    scalarExp->getCPPLiteralString(cg).c_str());
        } else {
          exp->outputCPP(cg, ar);
        }
      } else {
        cg_printf("\"%s\"", cg.escapeLabel(name).c_str());
      }
      if (isString) {
        cg_printf(")");
      }
    }
    cg_printf(";\n");
  }
  if (printed) {
    cg_printf("\n");
  }
}
Example #6
0
void InterfaceStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
    ClassScopeRawPtr classScope = getClassScope();

    if (cg.getOutput() == CodeGenerator::InlinedPHP ||
            cg.getOutput() == CodeGenerator::TrimmedPHP) {
        if (!classScope->isUserClass()) {
            return;
        }
    }

    cg_printf("interface %s", m_originalName.c_str());
    if (m_base) {
        cg_printf(" extends ");
        m_base->outputPHP(cg, ar);
    }
    cg_indentBegin(" {\n");
    classScope->outputPHP(cg, ar);
    if (m_stmt) m_stmt->outputPHP(cg, ar);
    cg_indentEnd("}\n");
}
Example #7
0
void FunctionScope::outputCPPCreateImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();
  string clsNameStr = scope->getId(cg);
  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,
                         cg.formatLabel(consName).c_str(),
                         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,
                           cg.formatLabel(consName).c_str(),
                           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,
                          cg.formatLabel(consName).c_str(), NULL, false);
      cg_indentEnd("}\n");
    }
  }
}
Example #8
0
void ConstantTable::outputCPPJumpTable(CodeGenerator &cg,
                                       AnalysisResultPtr ar,
                                       bool needsGlobals,
                                       bool ret) {
  bool system = cg.getOutput() == CodeGenerator::SystemCPP;
  vector<const char *> strings;
  if (!m_symbolVec.empty()) {
    strings.reserve(m_symbolVec.size());
    BOOST_FOREACH(Symbol *sym, m_symbolVec) {
      // Extension defined constants have no value but we are sure they exist
      if (!system && !sym->getValue()) continue;
      strings.push_back(sym->getName().c_str());
    }
  }
Example #9
0
void ConstantTable::outputCPPJumpTable(CodeGenerator &cg,
                                       AnalysisResultPtr ar,
                                       bool ret /* = true */) {
  bool system = cg.getOutput() == CodeGenerator::SystemCPP;
  bool hasDynamic = m_dynamic.size() > 0;
  vector<const char *> strings;
  if (!m_symbols.empty()) {
    strings.reserve(m_symbols.size());
    BOOST_FOREACH(string s, m_symbols) {
      // Extension defined constants have no value but we are sure they exist
      if (!system && !getValue(s)) continue;
      strings.push_back(s.c_str());
    }
  }
void IncludeExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  bool linemap = outputLineMap(cg, ar, true);

  // Includes aren't really supported in system mode
  if (cg.getOutput() == CodeGenerator::SystemCPP) {
    cg_printf("true");
    if (linemap) cg_printf(")");
    return;
  }
  const char *vars = m_privateScope ?
    "lvar_ptr(LVariableTable())" : "variables";
  bool require = (m_op == T_REQUIRE || m_op == T_REQUIRE_ONCE);
  bool once = (m_op == T_INCLUDE_ONCE || m_op == T_REQUIRE_ONCE);
  if (!getCurrentInclude(ar).empty()) {
    FileScopePtr fs = ar->findFileScope(getCurrentInclude(ar), false);
    if (fs) {
      cg_printf("%s%s(%s, %s)", Option::PseudoMainPrefix,
                fs->pseudoMainName().c_str(),
                once ? "true" : "false",
                vars);
      if (linemap) cg_printf(")");
      return;
    }
  }

  // include() and require() need containing file's directory
  string currentDir = "NULL";
  if (m_loc && m_loc->file && *m_loc->file) {
    string file = m_loc->file;
    size_t pos = file.rfind('/');
    if (pos != string::npos) {
      currentDir = '"';
      currentDir += file.substr(0, pos + 1);
      currentDir += '"';
    }
  }

  // fallback to dynamic include
  cg_printf("%s(", require ? "require" : "include");
  m_exp->outputCPP(cg, ar);
  cg_printf(", %s, %s, %s)",
            once ? "true" : "false",
            vars,
            currentDir.c_str());
  if (linemap) cg_printf(")");
}
void MethodStatement::outputCPPArgInjections(CodeGenerator &cg,
                                             AnalysisResultPtr ar,
                                             const char *name,
                                             ClassScopePtr cls,
                                             FunctionScopePtr funcScope) {
  if (cg.getOutput() != CodeGenerator::SystemCPP) {
    if (m_params) {
      int n = m_params->getCount();
      cg_printf("INTERCEPT_INJECTION(\"%s\", ", name);
      if (Option::GenArrayCreate && !hasRefParam()) {
        ar->m_arrayIntegerKeySizes.insert(n);
        outputParamArrayCreate(cg, true);
        cg_printf(", %s);\n", funcScope->isRefReturn() ? "ref(r)" : "r");
      } else {
        cg_printf("(Array(ArrayInit(%d, true)", n);
        for (int i = 0; i < n; i++) {
          ParameterExpressionPtr param =
            dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
          const string &paramName = param->getName();
          cg_printf(".set%s(%d, %s%s)", param->isRef() ? "Ref" : "",
                    i, Option::VariablePrefix, paramName.c_str());
        }
        cg_printf(".create())), %s);\n",
                  funcScope->isRefReturn() ? "ref(r)" : "r");
      }
    } else {
      cg_printf("INTERCEPT_INJECTION(\"%s\", null_array, %s);\n",
                name, funcScope->isRefReturn() ? "ref(r)" : "r");
    }
  }

  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(cls, funcScope, paramName);
        if (id != -1) {
          cg_printf("RTTI_INJECTION(%s%s, %d);\n",
                    Option::VariablePrefix, paramName.c_str(), id);
        }
      }
    }
  }
}
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg,
                                          AnalysisResultPtr ar,
                                          bool isVector,
                                          bool pre) {
  ASSERT(pre == !m_cppTemp.empty());
  if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) {
    return false;
  }
  if (hasNonArrayCreateValue()) return false;

  int64 max = m_exps.size();
  unsigned int n = isVector ? m_exps.size() : checkIntegerKeys(max);
  bool uniqIntegerKeys = false;
  bool uniqLitstrKeys = false;
  if (n > 0 && n == m_exps.size()) {
    uniqIntegerKeys = true;
  } else if (!isVector) {
    n = checkLitstrKeys();
    if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true;
  }
  if (uniqIntegerKeys) {
    ar->m_arrayIntegerKeySizes.insert(n);
  } else if (uniqLitstrKeys) {
    ar->m_arrayLitstrKeySizes.insert(n);
  } else {
    return false;
  }

  if (pre) {
    for (unsigned i = 0; i < m_exps.size(); i++) {
      if (ExpressionPtr exp = m_exps[i]) {
        exp->preOutputCPP(cg, ar, 0);
      }
    }
    cg_printf("ArrayInit %s(", m_cppTemp.c_str());
    outputCPPUniqLitKeyArrayInit(cg, ar, uniqIntegerKeys ? max : 0);
    cg_printf(");\n");
  } else if (uniqIntegerKeys) {
    outputCPPUniqLitKeyArrayInit(cg, ar, max);
  } else {
    outputCPPUniqLitKeyArrayInit(cg, ar, 0);
  }
  return true;
}
void ReturnStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  bool braced = false;
  FunctionScopePtr func = getFunctionScope();
  ClassScopePtr cls = getClassScope();
  if (func->isConstructor(cls)) {
    cg_indentBegin("{\n"); braced = true;
    cg_printf("gasInCtor(oldInCtor);\n");
  }
  if (m_exp) {
    if (m_exp->hasContext(Expression::RefValue)) {
      m_exp->setContext(Expression::NoRefWrapper);
    }
    m_exp->outputCPPBegin(cg, ar);
  }

  cg_printf("return");
  if (m_exp) {
    bool close = false;
    cg_printf(" ");
    if (m_exp->hasContext(Expression::RefValue) && m_exp->isRefable()) {
      cg_printf("strongBind(");
      close = true;
    } else if (checkCopyElision(func, m_exp)) {
      cg_printf("wrap_variant(");
      close = true;
    }
    m_exp->outputCPP(cg, ar);
    if (close) cg_printf(")");
    cg_printf(";\n");
    cg.setReferenceTempUsed(false);
    m_exp->outputCPPEnd(cg, ar);
  } else if (func &&
             !(func->inPseudoMain() && !Option::GenerateCPPMain &&
               cg.getOutput() != CodeGenerator::SystemCPP)) {
    TypePtr type = func->getReturnType();
    if (type) {
      const char *initializer = type->getCPPInitializer();
      cg_printf(" %s", initializer ? initializer : "null");
    }
    cg_printf(";\n");
  }

  if (braced) cg_indentEnd("}\n");
}
Example #14
0
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
  bool decl = true;
  if (cg.getContext() == CodeGenerator::CppConstantsDecl) {
    decl = false;
  }

  bool printed = false;
  for (StringToConstructPtrMap::const_iterator iter = m_declarations.begin();
       iter != m_declarations.end(); ++iter) {
    const string &name = iter->first;
    if (isSystem(name) && cg.getOutput() != CodeGenerator::SystemCPP) continue;

    ConstructPtr value = getValue(name);
    if (isDynamic(name)) continue;
    printed = true;

    cg.printf(decl ? "extern const " : "const ");
    TypePtr type = getFinalType(name);
    if (type->is(Type::KindOfString)) {
      cg.printf("StaticString");
    } else {
      type->outputCPPDecl(cg, ar);
    }
    const char *nameStr = name.c_str();
    if (decl) {
      cg.printf(" %s%s", Option::ConstantPrefix, nameStr);
    } else {
      cg.printf(" %s%s = ", Option::ConstantPrefix, nameStr);
      if (value) {
        ExpressionPtr exp = dynamic_pointer_cast<Expression>(value);
        ASSERT(!exp->getExpectedType());
        exp->outputCPP(cg, ar);
      } else {
        cg.printf("\"%s\"", nameStr);
      }
    }
    cg.printf(";\n");
  }
  if (printed) {
    cg.printf("\n");
  }
}
Example #15
0
bool FunctionScope::outputCPPInvokeArgCountCheck(CodeGenerator &cg,
    AnalysisResultPtr ar, bool ret, bool constructor) {
  bool variable = isVariableArgument();
  // system function has different handling of argument counts
  bool system = (m_system || m_sep ||
                 cg.getOutput() == CodeGenerator::SystemCPP);
  if (!system) {
    ClassScopePtr scope = ar->getClassScope();
    if (scope) system = (!scope->isUserClass() || scope->isExtensionClass() ||
                         scope->isSepExtension());
  }

  bool checkMissing = (m_minParam > 0);
  bool checkTooMany = (!variable && (system ||
                                     RuntimeOption::ThrowTooManyArguments));
  const char *sysret = (system && ret) ? "return " : "";
  const char *level = (system ? (constructor ? ", 2" : ", 1") : "");
  bool guarded = system && (ret || constructor);
  string fullname = getOriginalFullName();
  if (checkMissing && checkTooMany) {
    if (!variable && m_minParam == m_maxParam) {
      cg_printf("if (count != %d)"
                " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n",
                m_minParam, sysret, fullname.c_str(), m_minParam, m_maxParam,
                level);
    } else {
      cg_printf("if (count < %d || count > %d)"
                " %sthrow_wrong_arguments(\"%s\", count, %d, %d%s);\n",
                m_minParam, m_maxParam, sysret, fullname.c_str(),
                m_minParam, variable ? -1 : m_maxParam, level);
    }
  } else if (checkMissing) {
    cg_printf("if (count < %d)"
              " %sthrow_missing_arguments(\"%s\", count+1%s);\n",
              m_minParam, sysret, fullname.c_str(), level);
  } else if (checkTooMany) {
    cg_printf("if (count > %d)"
              " %sthrow_toomany_arguments(\"%s\", %d%s);\n",
              m_maxParam, sysret, fullname.c_str(), m_maxParam, level);
  }
  return guarded;
}
Example #16
0
void FunctionScope::outputCPPCreateDecl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();

  cg.printf("public: %s%s *create(",
            Option::ClassPrefix, scope->getId().c_str());
  outputCPPParamsDecl(cg, ar,
                      dynamic_pointer_cast<MethodStatement>(getStmt())
                      ->getParams(), true);
  cg.printf(");\n");
  cg.printf("public: ObjectData *dynCreate(CArrRef params, bool init = true);"
            "\n");
  if (isDynamic()) {
    cg.printf("public: void dynConstruct(CArrRef params);\n");
    if (cg.getOutput() == CodeGenerator::SystemCPP ||
        Option::EnableEval >= Option::LimitedEval) {
      cg.printf("public: void dynConstructFromEval(Eval::VariableEnvironment "
                "&env, const Eval::FunctionCallExpression *call);\n");
    }
  }
}
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();
}
Example #18
0
void ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg,
                                         AnalysisResultPtr ar,
                                         Type2SymbolListMap &type2names) {
  const char *prefix = Option::ConstantPrefix;
  string classId;
  const char *fmt = "";
  ClassScopePtr scope = getClassScope();
  if (scope) {
    prefix = Option::ClassConstantPrefix;
    classId = scope->getId(cg);
    fmt = "_";
  }

  bool system = cg.getOutput() == CodeGenerator::SystemCPP;

  SymbolList &symbols = type2names["Variant"];
  BOOST_FOREACH(Symbol *sym, m_symbolVec) {
    if (sym->declarationSet() && sym->isDynamic() &&
        system == sym->isSystem()) {
      symbols.push_back(string(prefix) + classId + fmt +
                        cg.formatLabel(sym->getName()));
    }
  }
}
Example #19
0
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,
                cg.formatLabel(m_name).c_str(),
                Option::ClassStaticsPrefix, classScope->getId(cg).c_str());
      cg_printf("g->%s%s = &%s%s;\n",
                Option::ClassStaticsCallbackPrefix,
                cg.formatLabel(m_name).c_str(),
                Option::ClassWrapperFunctionPrefix,
                classScope->getId(cg).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().c_str());
      }
    }
    return;
  }

  if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
    printSource(cg);
  }

  ar->pushScope(classScope);
  string clsNameStr = classScope->getId(cg);
  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);
        if (parCls && parCls->isRedeclaring()) parCls.reset();
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)) {
        if (!parCls) {
          cg_printf(" : public DynamicObjectData");
        } else {
          cg_printf(" : public %s%s", Option::ClassPrefix,
                    parCls->getId(cg).c_str());
        }
      } else {
        if (classScope->derivesFromRedeclaring()) {
          cg_printf(" : public DynamicObjectData");
        } else if (system) {
          cg_printf(" : public ExtObjectData");
        } else {
          cg_printf(" : public ObjectData");
        }
      }
      if (m_base && Option::UseVirtualDispatch) {
        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 && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(ar, intf) &&
              (!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
            string id = intfClassScope->getId(cg);
            cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      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());
        }
        if (classScope->derivesFromRedeclaring()) {
          cg_printf("CLASS_MAP_REDECLARED()\n");
        }
        cg_indentEnd("END_CLASS_MAP(%s)\n", clsName);
      }

      if (Option::GenerateCPPMacros) {
        bool dyn = (!parCls && !m_parent.empty()) ||
          classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = parCls && classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();
        if (!classScope->derivesFromRedeclaring()) {
          outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
                             parCls ? parCls->getId(cg).c_str() : "ObjectData");
        } else {
          cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    dyn || !parCls ? "DynamicObjectData" :
                    parCls->getId(cg).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(cg) +
              "(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");
      }

      classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
    }
    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);

    // This is lame. Exception base class needs to prepare stacktrace outside
    // of its PHP constructor. Every subclass of exception also needs this
    // stacktrace, so we're adding an artificial __init__ in exception.php
    // and calling it here.
    if (m_name == "exception") {
      cg_printf("{CountableHelper h(this); t___init__();}\n");
    }

    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->derivesDirectlyFrom(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().c_str());
      }
      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, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      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 ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
                                                    AnalysisResultPtr ar,
                                                    bool directVariant,
                                                    int doExist) {
  bool bThis = m_object->isThis();
  bool useGetThis = false;
  FunctionScopePtr funcScope = ar->getFunctionScope();
  if (bThis) {
    if (funcScope && funcScope->isStatic()) {
      cg_printf("GET_THIS_ARROW()");
    } else {
      // in order for __set() and __get() to be called
      useGetThis = true;
    }
  }

  const char *op = ".";
  string func = Option::ObjectPrefix;
  const char *error = ", true";
  ClassScopePtr cls = ar->getClassScope();
  const char *context = "";
  if (cg.getOutput() != CodeGenerator::SystemCPP) {
    if (cls) {
      context = ", s_class_name";
    } else if (funcScope && !funcScope->inPseudoMain()) {
      context = ", empty_string";
    }
  }
  if (doExist) {
    func = doExist > 0 ? "doIsSet" : "doEmpty";
    error = "";
  } else {
    if (bThis && funcScope && funcScope->isStatic()) {
      func = Option::ObjectStaticPrefix;
      error = "";
      context = "";
    } else if (m_context & ExistContext) {
      error = ", false";
    }
    if (m_context & (LValue | RefValue | UnsetContext)) {
      func += "lval";
      error = "";
    } else {
      func += "get";
    }
  }

  if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
    ScalarExpressionPtr name =
      dynamic_pointer_cast<ScalarExpression>(m_property);
    const char *propName = name->getString().c_str();
    if (m_valid && m_object->getType()->isSpecificObject()) {
      if (m_static) {
        if (!bThis) {
          ASSERT(m_class);
          if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty(");
          cg_printf("g->%s%s%s%s",
                    Option::StaticPropertyPrefix, m_class->getName().c_str(),
                    Option::IdPrefix.c_str(), propName);
          if (doExist) cg_printf(")");
        } else {
          // if $val is a class static variable (static $val), then $val
          // cannot be declared as a class variable (var $val), $this->val
          // refers to a non-static class variable and has to use get/lval.
          if (useGetThis) cg_printf("GET_THIS_DOT()");
          cg_printf("%s(", func.c_str());
          cg_printString(propName, ar);
          cg_printf("%s%s)", error, context);
        }
      } else {
        if (doExist) cg_printf(doExist > 0 ? "isset(" : "empty(");
        if (!bThis) {
          ASSERT(!directVariant);
          m_object->outputCPP(cg, ar);
          cg_printf("->");
        }
        cg_printf("%s%s", Option::PropertyPrefix, propName);
        if (doExist) cg_printf(")");
      }
    } else {
      if (!bThis) {
        if (directVariant) {
          TypePtr expectedType = m_object->getExpectedType();
          ASSERT(expectedType->is(Type::KindOfObject));
          // Clear m_expectedType to avoid type cast (toObject).
          m_object->setExpectedType(TypePtr());
          m_object->outputCPP(cg, ar);
          m_object->setExpectedType(expectedType);
        } else {
          m_object->outputCPP(cg, ar);
        }
        cg_printf(op);
      } else {
        if (useGetThis) cg_printf("GET_THIS_DOT()");
      }
      cg_printf("%s(", func.c_str());
      cg_printString(propName, ar);
      cg_printf("%s%s)", error, context);
    }
  } else {
    if (!bThis) {
      if (directVariant) {
        TypePtr expectedType = m_object->getExpectedType();
        ASSERT(expectedType->is(Type::KindOfObject));
        // Clear m_expectedType to avoid type cast (toObject).
        m_object->setExpectedType(TypePtr());
        m_object->outputCPP(cg, ar);
        m_object->setExpectedType(expectedType);
      } else {
        m_object->outputCPP(cg, ar);
      }
      cg_printf(op);
    } else {
      if (useGetThis) cg_printf("GET_THIS_DOT()");
    }
    cg_printf("%s(", func.c_str());
    m_property->outputCPP(cg, ar);
    cg_printf("%s%s)", error, context);
  }
}
Example #21
0
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
    if (m_arrayId != -1) {
        if (cg.getOutput() == CodeGenerator::SystemCPP) {
            cg.printf("SystemScalarArrays::%s[%d]",
                      Option::SystemScalarArrayName, m_arrayId);
        } else {
            cg.printf("ScalarArrays::%s[%d]",
                      Option::ScalarArrayName, m_arrayId);
        }
        return;
    }

    if ((m_op == T_ISSET || m_op == T_EMPTY) && m_exp) {
        if (m_exp->is(Expression::KindOfExpressionList)) {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (exps->getCount() > 1) {
                cg.printf("(");
            }
            for (int i = 0; i < exps->getCount(); i++) {
                if (i > 0) cg.printf(" && ");
                (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
            }
            if (exps->getCount() > 1) {
                cg.printf(")");
            }
        } else {
            m_exp->outputCPPExistTest(cg, ar, m_op);
        }
        return;
    }

    if (m_front) {
        switch (m_op) {
        case T_CLONE:
            cg.printf("f_clone(");
            break;
        case T_INC:
            cg.printf("++");
            break;
        case T_DEC:
            cg.printf("--");
            break;
        case '+':
            cg.printf("+");
            break;
        case '-':
            cg.printf("negate(");
            break;
        case '!':
            cg.printf("!(");
            break;
        case '~':
            cg.printf("~");
            break;
        case '(':
            cg.printf("(");
            break;
        case T_INT_CAST:
            cg.printf("(");
            break;
        case T_DOUBLE_CAST:
            cg.printf("(");
            break;
        case T_STRING_CAST:
            cg.printf("(");
            break;
        case T_ARRAY_CAST:
            cg.printf("(");
            break;
        case T_OBJECT_CAST:
            cg.printf("(");
            break;
        case T_BOOL_CAST:
            cg.printf("(");
            break;
        case T_UNSET_CAST:
            cg.printf("unset(");
            break;
        case T_EXIT:
            cg.printf("f_exit(");
            break;
        case T_ARRAY:
            if (ar->getInsideScalarArray()) {
                cg.printf("StaticArray(");
            } else {
                cg.printf("Array(");
            }
            break;
        case T_PRINT:
            cg.printf("print(");
            break;
        case T_EVAL:
            if (Option::EnableEval > Option::NoEval) {
                cg.printf("eval(%s, Object(%s), ",
                          ar->getScope()->inPseudoMain() ?
                          "get_variable_table()" : "variables",
                          ar->getClassScope() ? "this" : "");
            } else {
                cg.printf("f_eval(");
            }
            break;
        case '@':
            cg.printf("(%s%d.enable(),%s%d.disable(",
                      Option::SilencerPrefix, m_silencer,
                      Option::SilencerPrefix, m_silencer);
            break;
        case T_FILE:
            cg.printf("get_source_filename(\"%s\")", getLocation()->file);
            break;
            break;
        default:
            ASSERT(false);
        }
    }


    if (m_exp) {
        switch (m_op) {
        case '+':
        case '-':
            if (m_exp->getActualType() &&
                    (m_exp->getActualType()->is(Type::KindOfString) ||
                     m_exp->getActualType()->is(Type::KindOfArray))) {
                cg.printf("(Variant)(");
                m_exp->outputCPP(cg, ar);
                cg.printf(")");
            } else {
                m_exp->outputCPP(cg, ar);
            }
            break;
        case '@':
            // Void needs to return something to silenceDec
            if (!m_exp->getActualType()) {
                cg.printf("(");
                m_exp->outputCPP(cg, ar);
                cg.printf(",null)");
            } else {
                m_exp->outputCPP(cg, ar);
            }
            break;
        default:
            m_exp->outputCPP(cg, ar);
            break;
        }
    }

    if (m_front) {
        switch (m_op) {
        case T_ARRAY:
        {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (!exps) {
                cg.printf("ArrayData::Create()");
            }
            cg.printf(")");
        }
        break;
        case T_CLONE:
        case '!':
        case '(':
        case '-':
        case T_INT_CAST:
        case T_DOUBLE_CAST:
        case T_STRING_CAST:
        case T_ARRAY_CAST:
        case T_OBJECT_CAST:
        case T_BOOL_CAST:
        case T_UNSET_CAST:
        case T_EXIT:
        case T_PRINT:
        case T_EVAL:
        case T_INCLUDE:
        case T_INCLUDE_ONCE:
        case T_REQUIRE:
        case T_REQUIRE_ONCE:
            cg.printf(")");
            break;
        case '@':
            cg.printf("))");
            break;
        default:
            break;
        }
    } else {
        switch (m_op) {
        case T_INC:
            cg.printf("++");
            break;
        case T_DEC:
            cg.printf("--");
            break;
        default:
            ASSERT(false);
        }
    }
}
Example #22
0
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();
}
Example #23
0
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopeRawPtr classScope = getClassScope();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isVolatile()) {
      string name = cg.formatLabel(m_name);
      if (classScope->isRedeclaring()) {
        cg_printf("g->%s%s = ClassStaticsPtr(NEWOBJ(%s%s)());\n",
                  Option::ClassStaticsObjectPrefix,
                  name.c_str(),
                  Option::ClassStaticsPrefix, classScope->getId(cg).c_str());
        cg_printf("g->%s%s = &%s%s;\n",
                  Option::ClassStaticsCallbackPrefix,
                  name.c_str(),
                  Option::ClassWrapperFunctionPrefix,
                  classScope->getId(cg).c_str());
      }
      cg_printf("g->CDEC(%s) = true;\n", name.c_str());

      const vector<string> &bases = classScope->getBases();
      for (vector<string>::const_iterator it = bases.begin();
           it != bases.end(); ++it) {
        if (cg.checkHoistedClass(*it)) continue;
        ClassScopePtr base = ar->findClass(*it);
        if (base && base->isVolatile()) {
          cg_printf("checkClassExists(");
          cg_printString(base->getOriginalName(), ar, shared_from_this());
          string lname = Util::toLower(base->getOriginalName());
          cg_printf(", &%s->CDEC(%s), %s->FVF(__autoload));\n",
                    cg.getGlobals(ar), cg.formatLabel(lname).c_str(),
                    cg.getGlobals(ar));
        }
      }
    }
    return;
  }

  if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
    printSource(cg);
  }

  string clsNameStr = classScope->getId(cg);
  const char *clsName = clsNameStr.c_str();
  bool redeclared = classScope->isRedeclaring();
  switch (cg.getContext()) {
  case CodeGenerator::CppDeclaration:
    {
      if (Option::GenerateCPPMacros) {
        classScope->outputForwardDeclaration(cg);
      }

      bool system = cg.getOutput() == CodeGenerator::SystemCPP;
      ClassScopePtr parCls;
      if (!m_parent.empty()) {
        parCls = ar->findClass(m_parent);
        if (parCls && parCls->isRedeclaring()) parCls.reset();
      }
      if (Option::GenerateCppLibCode) {
        cg.printDocComment(classScope->getDocComment());
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)) {
        if (!parCls) {
          cg_printf(" : public DynamicObjectData");
        } else {
          cg_printf(" : public %s%s", Option::ClassPrefix,
                    parCls->getId(cg).c_str());
        }
      } else {
        if (classScope->derivesFromRedeclaring()) {
          cg_printf(" : public DynamicObjectData");
        } else if (system) {
          cg_printf(" : public ExtObjectData");
        } else {
          cg_printf(" : public ObjectData");
        }
      }
      if (m_base && Option::UseVirtualDispatch) {
        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 && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(intf) &&
              (!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
            string id = intfClassScope->getId(cg);
            cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      cg_indentBegin(" {\n");
      cg_printf("public:\n");

      cg.printSection("Properties");
      classScope->getVariables()->outputCPPPropertyDecl(cg, ar,
          classScope->derivesFromRedeclaring());

      if (Option::GenerateCppLibCode) {
        cg.printSection("Methods");
        classScope->outputMethodWrappers(cg, ar);
        cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<");
        cg_printf("// NOTE: Anything below is subject to change. "
                  "Use everything above instead.\n");
      }

      cg.printSection("Class Map");
      if (Option::GenerateCPPMacros) {
        cg_printf("virtual bool o_instanceof(CStrRef s) const;\n");
      }

      if (Option::GenerateCPPMacros) {
        bool dyn = (!parCls && !m_parent.empty()) ||
          classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = parCls && classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();
        if (!classScope->derivesFromRedeclaring()) {
          outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
                             parCls ? parCls->getId(cg).c_str()
                                    : "ObjectData");
        } else {
          cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    dyn || !parCls ? "DynamicObjectData" :
                    parCls->getId(cg).c_str());
        }

        bool hasGet = classScope->getAttribute(
          ClassScope::HasUnknownPropGetter);
        bool hasSet = classScope->getAttribute(
          ClassScope::HasUnknownPropSetter);
        bool hasCall = classScope->getAttribute(
          ClassScope::HasUnknownMethodHandler);
        bool hasCallStatic = classScope->getAttribute(
          ClassScope::HasUnknownStaticMethodHandler);

        if (dyn || idyn || redec || hasGet || hasSet ||
            hasCall || hasCallStatic) {
          if (redec && classScope->derivedByDynamic()) {
            if (!dyn && !idyn) {
              cg_printf("private: ObjectData* root;\n");
              cg_printf("public:\n");
              cg_printf("virtual ObjectData *getRoot() { return root; }\n");
            }
          }

          string conInit = "";
          bool hasParam = false;
          if (dyn) {
            conInit = " : DynamicObjectData(\"" + m_parent + "\", r)";
            hasParam = true;
          } else if (idyn) {
            conInit = " : " + string(Option::ClassPrefix) + parCls->getId(cg) +
              "(r ? r : this)";
            hasParam = true;
          } else {
            if (redec && classScope->derivedByDynamic()) {
              conInit = " : root(r ? r : this)";
            }
            hasParam = true;
          }

          cg_indentBegin("%s%s(%s)%s {%s",
                         Option::ClassPrefix, clsName,
                         hasParam ? "ObjectData* r = NULL" : "",
                         conInit.c_str(),
                         hasGet || hasSet || hasCall || hasCallStatic ?
                         "\n" : "");
          if (hasGet) cg_printf("setAttribute(UseGet);\n");
          if (hasSet) cg_printf("setAttribute(UseSet);\n");
          if (hasCall) cg_printf("setAttribute(HasCall);\n");
          if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n");
          cg_indentEnd("}\n");
        }
      }

      cg_printf("void init();\n");

      if (classScope->needLazyStaticInitializer()) {
        cg_printf("static GlobalVariables *lazy_initializer"
                  "(GlobalVariables *g);\n");
      }

      if (!classScope->getAttribute(ClassScope::HasConstructor)) {
        FunctionScopePtr func = classScope->findFunction(ar, "__construct",
                                                         false);
        if (func && !func->isAbstract() && !classScope->isInterface()) {
          func->outputCPPCreateDecl(cg, ar);
        }
      }
      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");
      }

      if (classScope->isRedeclaring() &&
          !classScope->derivesFromRedeclaring() &&
          classScope->derivedByDynamic()) {
        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);
      }
      if (Option::GenerateCPPMacros) {
        classScope->outputCPPJumpTableDecl(cg, ar);
      }
      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(CStrRef s) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sgetInit(s);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sget(CStrRef s) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sget(s);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant &%slval(CStrRef s) {\n",
                  Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%slval(s);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Object createOnly(ObjectData* root = NULL) {\n");
        cg_printf("Object r((NEWOBJ(%s%s)(root)));\n", Option::ClassPrefix,
            clsName);
        cg_printf("r->init();\n");
        cg_printf("return r;\n");
        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("bool %sget_call_info(MethodCallPackage &mcp, "
          "int64 hash = -1) {\n",
            Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sget_call_info(mcp, hash);\n",
            Option::ClassPrefix, clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentEnd("};\n");
      }

      if (m_stmt) {
        cg.setContext(CodeGenerator::CppClassConstantsDecl);
        m_stmt->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::CppDeclaration);
      }

      classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
    }
    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 {

        ClassScopePtr parCls = ar->findClass(m_parent);
        cg_printf("%s%s::init();\n", Option::ClassPrefix,
                  parCls->getId(cg).c_str());
      }
    }
    if (classScope->getVariables()->
        getAttribute(VariableTable::NeedGlobalPointer)) {
      cg.printDeclareGlobals();
    }
    cg.setContext(CodeGenerator::CppConstructor);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    // This is lame. Exception base class needs to prepare stacktrace outside
    // of its PHP constructor. Every subclass of exception also needs this
    // stacktrace, so we're adding an artificial __init__ in exception.php
    // and calling it here.
    if (m_name == "exception") {
      cg_printf("{CountableHelper h(this); t___init__();}\n");
    }

    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->derivesDirectlyFrom(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().c_str());
      }
      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, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      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;
  }
}
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {

  if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return;

  bool wrapped = true;
  switch (m_op) {
  case T_CONCAT_EQUAL:
    if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) {
      SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1);
      ExpressionPtrVec ev;
      bool hasVoid = false;
      getConcatList(ev, m_exp2, hasVoid);
      cg_printf("%s", stringBufferName(Option::TempPrefix, prefix,
                                       sv->getName().c_str()).c_str());
      outputStringBufExprs(ev, cg, ar);
      return;
    }
    cg_printf("concat_assign");
    break;
  case '.':
    {
      ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
      ExpressionPtrVec ev;
      bool hasVoid = false;
      int num = getConcatList(ev, self, hasVoid);
      assert(!hasVoid);
      if ((num <= MAX_CONCAT_ARGS ||
           (Option::GenConcat &&
            cg.getOutput() != CodeGenerator::SystemCPP))) {
        assert(num >= 2);
        if (num == 2) {
          cg_printf("concat(");
        } else {
          if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num);
          cg_printf("concat%d(", num);
        }
        for (size_t i = 0; i < ev.size(); i++) {
          ExpressionPtr exp = ev[i];
          if (i) cg_printf(", ");
          outputStringExpr(cg, ar, exp, false);
        }
        cg_printf(")");
      } else {
        cg_printf("StringBuffer()");
        outputStringBufExprs(ev, cg, ar);
        cg_printf(".detach()");
      }
    }
    return;
  case T_LOGICAL_XOR:         cg_printf("logical_xor");   break;
  case '|':                   cg_printf("bitwise_or");    break;
  case '&':                   cg_printf("bitwise_and");   break;
  case '^':                   cg_printf("bitwise_xor");   break;
  case T_IS_IDENTICAL:        cg_printf("same");          break;
  case T_IS_NOT_IDENTICAL:    cg_printf("!same");         break;
  case T_IS_EQUAL:            cg_printf("equal");         break;
  case T_IS_NOT_EQUAL:        cg_printf("!equal");        break;
  case '<':                   cg_printf("less");          break;
  case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more");      break;
  case '>':                   cg_printf("more");          break;
  case T_IS_GREATER_OR_EQUAL: cg_printf("not_less");      break;
  case '/':                   cg_printf("divide");        break;
  case '%':                   cg_printf("modulo");        break;
  case T_INSTANCEOF:          cg_printf("instanceOf");    break;
  default:
    wrapped = !isUnused();
    break;
  }

  if (wrapped) cg_printf("(");

  ExpressionPtr first = m_exp1;
  ExpressionPtr second = m_exp2;

  // we could implement these functions natively on String and Array classes
  switch (m_op) {
  case '+':
  case '-':
  case '*':
  case '/': {
    TypePtr actualType = first->getActualType();

    if (actualType &&
        (actualType->is(Type::KindOfString) ||
         (m_op != '+' && actualType->is(Type::KindOfArray)))) {
      cg_printf("(Variant)(");
      first->outputCPP(cg, ar);
      cg_printf(")");
    } else {
      bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope());
      first->outputCPP(cg, ar);
      if (flag) {
        cg_printf(")");
      }
    }
    break;
  }
  case T_SL:
  case T_SR:
    cg_printf("toInt64(");
    first->outputCPP(cg, ar);
    cg_printf(")");
    break;
  default:
    first->outputCPP(cg, ar);
    break;
  }

  switch (m_op) {
  case T_PLUS_EQUAL:          cg_printf(" += ");   break;
  case T_MINUS_EQUAL:         cg_printf(" -= ");   break;
  case T_MUL_EQUAL:           cg_printf(" *= ");   break;
  case T_DIV_EQUAL:           cg_printf(" /= ");   break;
  case T_MOD_EQUAL:           cg_printf(" %%= ");  break;
  case T_AND_EQUAL:           cg_printf(" &= ");   break;
  case T_OR_EQUAL:            cg_printf(" |= ");   break;
  case T_XOR_EQUAL:           cg_printf(" ^= ");   break;
  case T_SL_EQUAL:            cg_printf(" <<= ");  break;
  case T_SR_EQUAL:            cg_printf(" >>= ");  break;
  case T_BOOLEAN_OR:          cg_printf(" || ");   break;
  case T_BOOLEAN_AND:         cg_printf(" && ");   break;
  case T_LOGICAL_OR:          cg_printf(" || ");   break;
  case T_LOGICAL_AND:         cg_printf(" && ");   break;
  default:
    switch (m_op) {
    case '+':                   cg_printf(" + ");    break;
    case '-':                   cg_printf(" - ");    break;
    case '*':                   cg_printf(" * ");    break;
    case T_SL:                  cg_printf(" << ");   break;
    case T_SR:                  cg_printf(" >> ");   break;
    default:
      cg_printf(", ");
      break;
    }
    break;
  }

  switch (m_op) {
  case '+':
  case '-':
  case '*':
  case '/': {
    TypePtr actualType = second->getActualType();

    if (actualType &&
        (actualType->is(Type::KindOfString) ||
         (m_op != '+' && actualType->is(Type::KindOfArray)))) {
      cg_printf("(Variant)(");
      second->outputCPP(cg, ar);
      cg_printf(")");
    } else {
      bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope());
      second->outputCPP(cg, ar);
      if (flag) {
        cg_printf(")");
      }
    }
    break;
  }
  case T_INSTANCEOF:
    {
      if (second->isScalar()) {
        std::string s = second->getLiteralString();
        std::string sLower = Util::toLower(s);
        if (sLower != "") {
          cg_printString(sLower, ar, shared_from_this());
        } else {
          second->outputCPP(cg, ar);
        }
      } else {
        second->outputCPP(cg, ar);
      }
      break;
    }
  case T_PLUS_EQUAL:
  case T_MINUS_EQUAL:
  case T_MUL_EQUAL:
    {
      TypePtr t1 = first->getCPPType();
      TypePtr t2 = second->getType();
      if (t1 && !t1->is(Type::KindOfArray) &&
          t2 && Type::IsCastNeeded(ar, t2, t1)) {
        t1->outputCPPCast(cg, ar, getScope());
        cg_printf("(");
        second->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        second->outputCPP(cg, ar);
      }
      break;
    }
  case T_BOOLEAN_OR:
  case T_BOOLEAN_AND:
  case T_LOGICAL_AND:
  case T_LOGICAL_OR:
    if (isUnused()) {
      cg_printf("(");
      if (second->outputCPPUnneeded(cg, ar)) {
        cg_printf(",");
      }
      cg_printf("false)");
    } else {
      second->outputCPP(cg, ar);
    }
    break;
  default:
    second->outputCPP(cg, ar);
  }

  if (wrapped) cg_printf(")");
}
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
        AnalysisResultPtr ar,
        int doExist) {
    string func = Option::ObjectPrefix;
    const char *error = ", true";
    std::string context = "";
    bool doUnset = m_context & LValue && m_context & UnsetContext;
    bool needTemp = false;

    if (cg.getOutput() != CodeGenerator::SystemCPP) {
        context = originalClassName(cg, true);
    }
    if (doUnset) {
        func = "o_unset";
        error = "";
    } else if (doExist) {
        func = doExist > 0 ? "o_isset" : "o_empty";
        error = "";
    } else {
        if (m_context & ExistContext) {
            error = ", false";
        }
        if (m_context & InvokeArgument) {
            ASSERT(cg.callInfoTop() != -1);
            func += "argval";
        } else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) {
            if (m_context & UnsetContext) {
                assert(!(m_context & LValue)); // handled by doUnset
                func += "unsetLval";
            } else {
                func += "lval";
            }
            error = "";
            needTemp = true;
        } else {
            func += "get";
            if (isNonPrivate(ar)) {
                func += "Public";
                context = "";
            }
        }
    }

    if (m_valid && doExist) cg_printf(doExist > 0 ? "isset(" : "empty(");
    bool flag = outputCPPObject(cg, ar, doUnset || (!m_valid && doExist));
    if (flag) {
        cg_printf("id(");
        outputCPPProperty(cg, ar);
        cg_printf(")");
        if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true");
        cg_printf(")");
    } else if (!doUnset && m_valid) {
        assert(m_object->getType()->isSpecificObject());
        ScalarExpressionPtr name =
            dynamic_pointer_cast<ScalarExpression>(m_property);
        cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str());
        if (doExist) cg_printf(")");
    } else {
        cg_printf("%s(", func.c_str());
        if (hasContext(InvokeArgument)) {
            cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
        }
        outputCPPProperty(cg, ar);
        if (needTemp) {
            const string &tmp = cg.getReferenceTemp();
            context = ", " + (tmp.empty() ? "Variant()" : tmp) + context;
        }
        cg_printf("%s%s)", error, context.c_str());
    }
}
bool BinaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                      int state) {
  if (isOpEqual()) return Expression::preOutputCPP(cg, ar, state);
  bool effect2 = m_exp2->hasEffect();
  const char *prefix = 0;
  if (effect2 || m_exp1->hasEffect()) {
    ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
    ExpressionPtrVec ev;
    bool hasVoid = false;
    int numConcat = 0;
    bool ok = false;
    if (m_op == '.') {
      numConcat = getConcatList(ev, self, hasVoid);
      ok = hasVoid ||
           (numConcat > MAX_CONCAT_ARGS &&
            (!Option::GenConcat ||
             cg.getOutput() == CodeGenerator::SystemCPP));
    } else if (effect2 && m_op == T_CONCAT_EQUAL) {
      prefix = stringBufferPrefix(cg, ar, m_exp1);
      ok = prefix;
      if (!ok) {
        if (m_exp1->is(KindOfSimpleVariable)) {
          ok = true;
          ev.push_back(m_exp1);
          numConcat++;
        }
      }
      numConcat += getConcatList(ev, m_exp2, hasVoid);
    }
    if (ok) {
      if (!cg.inExpression()) return true;

      cg.wrapExpressionBegin();
      std::string buf;
      if (prefix) {
        SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(m_exp1));
        buf = stringBufferName(Option::TempPrefix, prefix,
                               sv->getName().c_str());
        m_cppTemp = "/**/";
      } else if (numConcat) {
        buf = m_cppTemp = genCPPTemp(cg, ar);
        buf += "_buf";
        cg_printf("StringBuffer %s;\n", buf.c_str());
      } else {
        m_cppTemp = "\"\"";
      }

      for (size_t i = 0; i < ev.size(); i++) {
        ExpressionPtr exp = ev[i];
        bool is_void = !exp->getActualType();
        exp->preOutputCPP(cg, ar, 0);
        if (!is_void) {
          cg_printf("%s.append(", buf.c_str());
          outputStringExpr(cg, ar, exp, true);
          cg_printf(")");
        } else {
          exp->outputCPPUnneeded(cg, ar);
        }
        cg_printf(";\n");
      }

      if (numConcat && !prefix) {
        cg_printf("CStrRef %s(%s.detach());\n",
                  m_cppTemp.c_str(), buf.c_str());
        if (m_op == T_CONCAT_EQUAL) {
          m_exp1->outputCPP(cg, ar);
          cg_printf(" = %s;\n", m_cppTemp.c_str());
        }
      }
      return true;
    }
  }

  if (!isShortCircuitOperator()) {
    return Expression::preOutputCPP(cg, ar, state);
  }

  if (!effect2) {
    return m_exp1->preOutputCPP(cg, ar, state);
  }

  bool fix_e1 = m_exp1->preOutputCPP(cg, ar, 0);
  if (!cg.inExpression()) {
    return fix_e1 || m_exp2->preOutputCPP(cg, ar, 0);
  }

  cg.setInExpression(false);
  bool fix_e2 = m_exp2->preOutputCPP(cg, ar, 0);
  cg.setInExpression(true);

  if (fix_e2) {
    cg.wrapExpressionBegin();
    std::string tmp = genCPPTemp(cg, ar);
    cg_printf("bool %s = (", tmp.c_str());
    m_exp1->outputCPP(cg, ar);
    cg_printf(");\n");
    cg_indentBegin("if (%s%s) {\n",
                   m_op == T_LOGICAL_OR || m_op == T_BOOLEAN_OR ? "!" : "",
                   tmp.c_str());
    m_exp2->preOutputCPP(cg, ar, 0);
    cg_printf("%s = (", tmp.c_str());
    m_exp2->outputCPP(cg, ar);
    cg_printf(");\n");
    cg_indentEnd("}\n");
    m_cppTemp = tmp;
  } else if (state & FixOrder) {
    preOutputStash(cg, ar, state);
    fix_e1 = true;
  }
  return fix_e1 || fix_e2;
}
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  ClassScopePtr scope = getClassScope();

  if (outputFFI(cg, ar)) return;

  cg.setPHPLineNo(-1);

  CodeGenerator::Context context = cg.getContext();

  if (context == CodeGenerator::CppImplementation) {
    printSource(cg);
  }

  bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl ||
    context == CodeGenerator::CppTypedParamsWrapperImpl;

  bool needsWrapper = isWrapper ||
    (Option::HardTypeHints && funcScope->needsTypeCheckWrapper());

  const char *prefix = needsWrapper && !isWrapper ?
    Option::TypedMethodPrefix : Option::MethodPrefix;

  switch (context) {
    case CodeGenerator::CppDeclaration:
    case CodeGenerator::CppTypedParamsWrapperDecl:
    {
      if (!m_stmt && !funcScope->isPerfectVirtual()) {
        cg_printf("// ");
      }

      m_modifiers->outputCPP(cg, ar);

      if (!m_stmt || m_name == "__offsetget_lval" ||
          funcScope->isPerfectVirtual()) {
        cg_printf("virtual ");
      }
      TypePtr type = funcScope->getReturnType();
      if (type) {
        type->outputCPPDecl(cg, ar);
      } else {
        cg_printf("void");
      }
      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(CStrRef cls%s",
                  needsWrapper && !isWrapper ?
                  Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
                  cg.formatLabel(m_name).c_str(),
                  funcScope->isVariableArgument() ||
                  (m_params && m_params->getCount()) ? ", " : "");
      } else {
        cg_printf(" %s%s(", prefix, cg.formatLabel(m_name).c_str());
      }
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      if (m_stmt) {
        cg_printf(");\n");
      } else if (funcScope->isPerfectVirtual()) {
        cg_printf(") { return throw_fatal(\"pure virtual\");}\n");
      } else {
        cg_printf(") = 0;\n");
      }

      if (context != CodeGenerator::CppTypedParamsWrapperDecl) {
        if (funcScope->isConstructor(scope)
            && !funcScope->isAbstract() && !scope->isInterface()) {
          funcScope->outputCPPCreateDecl(cg, ar);
        }
        if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
          outputCPPImpl(cg, ar);
          cg.setContext(context);
        }
      }
    }
    break;
    case CodeGenerator::CppImplementation:
    case CodeGenerator::CppTypedParamsWrapperImpl:
      if (m_stmt) {
        TypePtr type = funcScope->getReturnType();
        if (type) {
          type->outputCPPDecl(cg, ar);
        } else {
          cg_printf("void");
        }
        string origFuncName = getOriginalFullName();
        string funcSection = Option::FunctionSections[origFuncName];
        if (!funcSection.empty()) {
          cg_printf(" __attribute__ ((section (\".text.%s\")))",
                    funcSection.c_str());
        }

        if (m_name == "__offsetget_lval") {
          cg_printf(" &%s%s::___offsetget_lval(",
                    Option::ClassPrefix, scope->getId(cg).c_str());
        } else if (m_modifiers->isStatic()) {
          cg_printf(" %s%s::%s%s(CStrRef cls%s", Option::ClassPrefix,
                    scope->getId(cg).c_str(),
                    needsWrapper && !isWrapper ?
                    Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
                    cg.formatLabel(m_name).c_str(),
                    funcScope->isVariableArgument() ||
                    (m_params && m_params->getCount()) ? ", " : "");
        } else {
          cg_printf(" %s%s::%s%s(", Option::ClassPrefix,
                    scope->getId(cg).c_str(),
                    prefix, cg.formatLabel(m_name).c_str());
        }
        funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
        cg_indentBegin(") {\n");
        if (context != CodeGenerator::CppTypedParamsWrapperImpl) {
          if (m_stmt->hasBody()) {
            const char *sys =
              (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : "");
            if (m_modifiers->isStatic()) {
              cg_printf("STATIC_METHOD_INJECTION%s(%s, %s);\n", sys,
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            } else if (cg.getOutput() != CodeGenerator::SystemCPP &&
                       !scope->isRedeclaring() && !scope->derivedByDynamic()) {
              cg_printf("INSTANCE_METHOD_INJECTION_ROOTLESS(%s, %s);\n",
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            } else {
              cg_printf("INSTANCE_METHOD_INJECTION%s(%s, %s);\n", sys,
                        scope->getOriginalName().c_str(), origFuncName.c_str());
            }
          }
          outputCPPArgInjections(cg, ar, origFuncName.c_str(),
                                 scope, funcScope);
          if (m_name == "__offsetget_lval") {
            ParameterExpressionPtr param =
              dynamic_pointer_cast<ParameterExpression>((*m_params)[0]);
            cg_printf("Variant &v = %s->__lvalProxy;\n", cg.getGlobals(ar));
            string lowered = Util::toLower(m_originalName);
            cg_printf("v = %s%s(%s%s);\n",
                      prefix, 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");
            }
            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_indentEnd("}\n");
          if (Option::HardTypeHints && funcScope->needsTypeCheckWrapper()) {
            cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl);
            outputCPPImpl(cg, ar);
          }
        } else {
          outputCPPTypeCheckWrapper(cg, ar);
          cg_indentEnd("}\n");
        }
        cg.setContext(context);
        cg.printImplSplitter();
      }
      break;
    default:
      break;
  }
}
void FunctionStatement::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  CodeGenerator::Context context = cg.getContext();

  FunctionScopeRawPtr funcScope = getFunctionScope();
  string fname = funcScope->getId(cg);
  bool pseudoMain = funcScope->inPseudoMain();
  string origFuncName = !pseudoMain ? funcScope->getOriginalName() :
          ("run_init::" + funcScope->getContainingFile()->getName());
  string funcSection;

  if (outputFFI(cg, ar)) return;

  if (context == CodeGenerator::NoContext) {
    string rname = cg.formatLabel(m_name);
    if (funcScope->isRedeclaring()) {
      cg.printf("g->GCI(%s) = &%s%s;\n", m_name.c_str(),
                Option::CallInfoPrefix, fname.c_str());
    }
    if (funcScope->isVolatile()) {
      cg_printf("g->declareFunctionLit(");
      cg_printString(m_name, ar, shared_from_this());
      cg_printf(");\n");
      cg_printf("g->FVF(%s) = true;\n", rname.c_str());
    }
    return;
  }

  if (context == CodeGenerator::CppDeclaration &&
      !funcScope->isInlined()) return;

  if (context == CodeGenerator::CppPseudoMain &&
      !pseudoMain) return;
  if (context == CodeGenerator::CppImplementation &&
      (funcScope->isInlined() || pseudoMain)) return;

  cg.setPHPLineNo(-1);

  if (pseudoMain && !Option::GenerateCPPMain) {
    if (context == CodeGenerator::CppPseudoMain) {
      if (cg.getOutput() != CodeGenerator::SystemCPP) {
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal);
        outputCPPStmt(cg, ar);
        funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal);
        cg.setContext(CodeGenerator::CppPseudoMain);
        return;
      }
    } else if (context == CodeGenerator::CppForwardDeclaration &&
               cg.getOutput() != CodeGenerator::SystemCPP) {
      return;
    }
  }

  if (context == CodeGenerator::CppImplementation) {
    printSource(cg);
  } else if (context == CodeGenerator::CppForwardDeclaration &&
             Option::GenerateCppLibCode) {
    cg_printf("\n");
    printSource(cg);
    cg.printDocComment(funcScope->getDocComment());
  }

  bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl ||
    context == CodeGenerator::CppTypedParamsWrapperImpl;

  bool needsWrapper = isWrapper ||
    (Option::HardTypeHints && funcScope->needsTypeCheckWrapper());

  if (funcScope->isInlined()) cg_printf("inline ");

  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar, getScope());
  } else {
    cg_printf("void");
  }

  funcSection = Option::FunctionSections[origFuncName];
  if (!funcSection.empty()) {
    cg_printf(" __attribute__ ((section (\".text.%s\")))",
              funcSection.c_str());
  }

  if (pseudoMain) {
    cg_printf(" %s%s(", Option::PseudoMainPrefix,
              funcScope->getContainingFile()->pseudoMainName().c_str());
  } else {
    cg_printf(" %s%s(",
              needsWrapper && !isWrapper ?
              Option::TypedFunctionPrefix : Option::FunctionPrefix,
              fname.c_str());
  }

  switch (context) {
    case CodeGenerator::CppForwardDeclaration:
    case CodeGenerator::CppTypedParamsWrapperDecl:
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      cg_printf(");\n");
      if (!isWrapper) {
        if (funcScope->hasDirectInvoke()) {
          cg_printf("Variant %s%s(void *extra, CArrRef params);\n",
                    Option::InvokePrefix, fname.c_str());
        }
        if (needsWrapper) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
          outputCPPImpl(cg, ar);
          cg.setContext(context);
        }
      }
      break;
    case CodeGenerator::CppDeclaration:
    case CodeGenerator::CppImplementation:
    case CodeGenerator::CppPseudoMain:
    case CodeGenerator::CppTypedParamsWrapperImpl:
    {
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg_indentBegin(") {\n");
      if (!isWrapper) {
        const char *sys =
          (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : "");
        if (pseudoMain) {
          cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n",
                    sys, origFuncName.c_str(), Option::PseudoMainPrefix,
                    funcScope->getContainingFile()->pseudoMainName().c_str());
        } else {
          if (m_stmt->hasBody()) {
            cg_printf("FUNCTION_INJECTION%s(%s);\n", sys,
                      origFuncName.c_str());
          }
          outputCPPArgInjections(cg, ar, origFuncName.c_str(),
                                 ClassScopePtr(), funcScope);
        }
        funcScope->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        outputCPPStmt(cg, ar);
        cg_indentEnd("}\n");
        if (needsWrapper) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl);
          outputCPPImpl(cg, ar);
        }
        cg.setContext(context);
      } else {
        outputCPPTypeCheckWrapper(cg, ar);
        cg_indentEnd("}\n");
      }
      cg.printImplSplitter();
    }
    break;
    default:
      ASSERT(false);
  }
}
Example #29
0
void FunctionStatement::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  CodeGenerator::Context context = cg.getContext();

  FunctionScopeRawPtr funcScope = getFunctionScope();
  string fname = funcScope->getId();
  bool pseudoMain = funcScope->inPseudoMain();
  string origFuncName = !pseudoMain ? funcScope->getOriginalName() :
          ("run_init::" + funcScope->getContainingFile()->getName());

  if (outputFFI(cg, ar)) return;

  if (context == CodeGenerator::NoContext) {
    funcScope->outputCPPDef(cg);
    return;
  }

  if (context == CodeGenerator::CppDeclaration &&
      !funcScope->isInlined()) return;

  if (context == CodeGenerator::CppPseudoMain &&
      (!pseudoMain || getFileScope()->canUseDummyPseudoMain(ar))) {
    return;
  }
  if (context == CodeGenerator::CppImplementation &&
      (funcScope->isInlined() || pseudoMain)) return;

  cg.setPHPLineNo(-1);

  if (pseudoMain && !Option::GenerateCPPMain) {
    if (context == CodeGenerator::CppPseudoMain) {
      if (cg.getOutput() != CodeGenerator::SystemCPP) {
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal);
        outputCPPStmt(cg, ar);
        funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal);
        cg.setContext(CodeGenerator::CppPseudoMain);
        return;
      }
    } else if (context == CodeGenerator::CppForwardDeclaration &&
               cg.getOutput() != CodeGenerator::SystemCPP) {
      return;
    }
  }

  if (context == CodeGenerator::CppImplementation) {
    printSource(cg);
  } else if (context == CodeGenerator::CppForwardDeclaration &&
             Option::GenerateCppLibCode) {
    cg_printf("\n");
    printSource(cg);
    cg.printDocComment(funcScope->getDocComment());
  }

  bool isWrapper = context == CodeGenerator::CppTypedParamsWrapperDecl ||
    context == CodeGenerator::CppTypedParamsWrapperImpl;

  bool needsWrapper = isWrapper ||
    (Option::HardTypeHints && funcScope->needsTypeCheckWrapper());

  int startLineImplementation = -1;
  if (context == CodeGenerator::CppDeclaration ||
      context == CodeGenerator::CppImplementation ||
      context == CodeGenerator::CppPseudoMain) {
    startLineImplementation = cg.getLineNo(CodeGenerator::PrimaryStream);
  }

  if (funcScope->isInlined()) cg_printf("inline ");

  TypePtr type = funcScope->getReturnType();
  if (type) {
    bool isHeader = cg.isFileOrClassHeader();
    cg.setFileOrClassHeader(true);
    type->outputCPPDecl(cg, ar, getScope());
    cg.setFileOrClassHeader(isHeader);
  } else {
    cg_printf("void");
  }

  if (Option::FunctionSections.find(origFuncName) !=
      Option::FunctionSections.end()) {
    string funcSection = Option::FunctionSections[origFuncName];
    if (!funcSection.empty()) {
      cg_printf(" __attribute__ ((section (\".text.%s\")))",
                funcSection.c_str());
    }
  }

  if (pseudoMain) {
    cg_printf(" %s%s(", Option::PseudoMainPrefix,
              funcScope->getContainingFile()->pseudoMainName().c_str());
  } else {
    cg_printf(" %s%s(",
              needsWrapper && !isWrapper ?
              Option::TypedFunctionPrefix : Option::FunctionPrefix,
              fname.c_str());
  }

  switch (context) {
    case CodeGenerator::CppForwardDeclaration:
    case CodeGenerator::CppTypedParamsWrapperDecl:
      funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
      if (!isWrapper) {
        int opt = Option::GetOptimizationLevel(m_cppLength);
        if (opt < 3) cg_printf(") __attribute__((optimize(%d))", opt);
      }
      cg_printf(");\n");
      if (!isWrapper) {
        if (funcScope->hasDirectInvoke()) {
          cg_printf("Variant %s%s(void *extra, CArrRef params);\n",
                    Option::InvokePrefix, fname.c_str());
        }
        if (needsWrapper) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
          outputCPPImpl(cg, ar);
          cg.setContext(context);
        }
      }
      break;
    case CodeGenerator::CppDeclaration:
    case CodeGenerator::CppImplementation:
    case CodeGenerator::CppPseudoMain:
    case CodeGenerator::CppTypedParamsWrapperImpl:
    {
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg_indentBegin(") {\n");
      if (!isWrapper) {
        const char *suffix =
          (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : "");
        if (pseudoMain) {
          cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n",
                    suffix, origFuncName.c_str(), Option::PseudoMainPrefix,
                    funcScope->getContainingFile()->pseudoMainName().c_str());
        } else {
          if (m_stmt->hasBody()) {
            if (suffix[0] == '\0' && !funcScope->needsCheckMem()) {
              suffix = "_NOMEM";
            }
            const string &name = funcScope->getInjectionId();
            cg_printf("FUNCTION_INJECTION%s(%s);\n", suffix, name.c_str());
          }
          outputCPPArgInjections(cg, ar, origFuncName.c_str(),
                                 ClassScopePtr(), funcScope);
        }
        funcScope->outputCPP(cg, ar);
        if (funcScope->needsRefTemp()) cg.genReferenceTemp(shared_from_this());
        if (funcScope->needsObjTemp()) {
          cg_printf("ObjectData *obj_tmp UNUSED;\n");
        }
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        outputCPPStmt(cg, ar);
        if (funcScope->needsRefTemp()) cg.clearRefereceTemp();
        cg_indentEnd("}\n");
        ASSERT(startLineImplementation >= 0);
        m_cppLength = cg.getLineNo(CodeGenerator::PrimaryStream)
                      - startLineImplementation;
        if (needsWrapper) {
          cg.setContext(CodeGenerator::CppTypedParamsWrapperImpl);
          outputCPPImpl(cg, ar);
        }
        cg.setContext(context);
      } else {
        outputCPPTypeCheckWrapper(cg, ar);
        cg_indentEnd("}\n");
      }
      cg.printImplSplitter();
    }
    break;
    default:
      ASSERT(false);
  }
}
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  if (cg.getContext() == CodeGenerator::NoContext) {
    InterfaceStatement::outputCPPImpl(cg, ar);
    return;
  }

  ClassScopeRawPtr classScope = getClassScope();
  if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
    printSource(cg);
  }

  string clsNameStr = classScope->getId();
  const char *clsName = clsNameStr.c_str();

  switch (cg.getContext()) {
  case CodeGenerator::CppDeclaration:
    {
      if (Option::GenerateCPPMacros) {
        classScope->outputForwardDeclaration(cg);
      }
      classScope->outputCPPGlobalTableWrappersDecl(cg, ar);

      bool system = cg.getOutput() == CodeGenerator::SystemCPP;
      ClassScopePtr parCls;
      if (!m_parent.empty()) {
        parCls = ar->findClass(m_parent);
        if (parCls && parCls->isRedeclaring()) parCls.reset();
      }
      if (Option::GenerateCppLibCode) {
        cg.printDocComment(classScope->getDocComment());
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)) {
        if (!parCls) {
          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");
        }
      }
      if (m_base && Option::UseVirtualDispatch) {
        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 && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(intf) &&
              (!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
            string id = intfClassScope->getId();
            cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      cg_indentBegin(" {\n");
      cg_printf("public:\n");

      cg.printSection("Properties");
      if (classScope->getVariables()->outputCPPPropertyDecl(
            cg, ar, classScope->derivesFromRedeclaring())) {
        cg.printSection("Destructor");
        cg_printf("~%s%s() NEVER_INLINE {}", Option::ClassPrefix, clsName);
      }

      if (Option::GenerateCppLibCode) {
        cg.printSection("Methods");
        classScope->outputMethodWrappers(cg, ar);
        cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<");
        cg_printf("// NOTE: Anything below is subject to change. "
                  "Use everything above instead.\n");
      }

      cg.printSection("Class Map");

      bool hasEmitCppCtor = false;
      bool needsCppCtor = classScope->needsCppCtor();
      bool needsInit    = classScope->needsInitMethod();

      bool disableDestructor =
        !classScope->canSkipCreateMethod(ar) ||
        (!classScope->derivesFromRedeclaring() &&
         !classScope->hasAttribute(ClassScope::HasDestructor, ar));

      if (Option::GenerateCPPMacros) {
        bool dyn = classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = parCls && classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();

        if (!parCls && !m_parent.empty()) {
          assert(dyn);
        }

        if (!classScope->derivesFromRedeclaring()) {
          outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
                             parCls ? parCls->getId().c_str()
                                    : "ObjectData");
        } else {
          cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    dyn || !parCls ? "DynamicObjectData" :
                    parCls->getId().c_str());
        }

        if (classScope->checkHasPropTable()) {
          cg_printf("static const ClassPropTable %sprop_table;\n",
                    Option::ObjectStaticPrefix);
        }

        bool hasGet = classScope->getAttribute(
          ClassScope::HasUnknownPropGetter);
        bool hasSet = classScope->getAttribute(
          ClassScope::HasUnknownPropSetter);
        bool hasIsset = classScope->getAttribute(
          ClassScope::HasUnknownPropTester);
        bool hasUnset = classScope->getAttribute(
          ClassScope::HasPropUnsetter);
        bool hasCall = classScope->getAttribute(
          ClassScope::HasUnknownMethodHandler);
        bool hasCallStatic = classScope->getAttribute(
          ClassScope::HasUnknownStaticMethodHandler);

        bool hasRootParam =
          classScope->derivedByDynamic() && (redec || dyn || idyn);
        string lateInit = "";
        if (redec && classScope->derivedByDynamic()) {
          if (!dyn && !idyn && (!parCls || parCls->isUserClass())) {
            cg_printf("private: ObjectData* root;\n");
            cg_printf("public:\n");
            cg_printf("virtual ObjectData *getRoot() { return root; }\n");
            lateInit = "root(r ? r : this)";
          }
        }

        string callbacks = Option::ClassStaticsCallbackPrefix + clsNameStr;
        string conInit = "";
        if (dyn) {
          conInit = "DynamicObjectData(cb, \"" +
            CodeGenerator::EscapeLabel(m_parent) + "\", ";
          if (hasRootParam) {
            conInit += "r)";
          } else {
            conInit += "this)";
          }
        } else if (parCls) {
          conInit = string(Option::ClassPrefix) + parCls->getId() + "(";
          if (parCls->derivedByDynamic() &&
              (parCls->isRedeclaring() ||
               parCls->derivesFromRedeclaring() != ClassScope::FromNormal)) {
            if (hasRootParam) {
              conInit += "r ? r : ";
            }
            conInit += "this, ";
          }
          conInit += "cb)";
        } else {
          if (system) {
            conInit = "ExtObjectData(cb)";
          } else {
            if (hasRootParam) {
              conInit = "ObjectData(cb, r)";
            } else {
              conInit = "ObjectData(cb, false)";
            }
          }
        }

        cg_printf("%s%s(%sconst ObjectStaticCallbacks *cb = &%s%s) : %s",
                  Option::ClassPrefix,
                  clsName,
                  hasRootParam ? "ObjectData* r = NULL," : "",
                  callbacks.c_str(),
                  redec ? ".oscb" : "",
                  conInit.c_str());

        if (needsCppCtor) {
          cg_printf(", ");
          cg.setContext(CodeGenerator::CppConstructor);
          ASSERT(!cg.hasInitListFirstElem());
          m_stmt->outputCPP(cg, ar);
          cg.clearInitListFirstElem();
          cg.setContext(CodeGenerator::CppDeclaration);
        }
        if (!lateInit.empty()) {
          cg_printf(", %s", lateInit.c_str());
        }

        cg_indentBegin(" {%s",
                       hasGet || hasSet || hasIsset || hasUnset ||
                       hasCall || hasCallStatic || disableDestructor ||
                       hasRootParam ? "\n" : "");
        if (hasRootParam) {
          cg_printf("setId(r);\n");
        }
        if (hasGet) cg_printf("setAttribute(UseGet);\n");
        if (hasSet) cg_printf("setAttribute(UseSet);\n");
        if (hasIsset) cg_printf("setAttribute(UseIsset);\n");
        if (hasUnset) cg_printf("setAttribute(UseUnset);\n");
        if (hasCall) cg_printf("setAttribute(HasCall);\n");
        if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n");
        if (disableDestructor) {
          cg_printf("if (!hhvm) setAttribute(NoDestructor);\n");
        }
        cg_indentEnd("}\n");
        hasEmitCppCtor = true;
      }

      if (needsCppCtor && !hasEmitCppCtor) {
        cg_printf("%s%s() : ", Option::ClassPrefix, clsName);
        cg.setContext(CodeGenerator::CppConstructor);
        ASSERT(!cg.hasInitListFirstElem());
        m_stmt->outputCPP(cg, ar);
        cg.clearInitListFirstElem();
        cg.setContext(CodeGenerator::CppDeclaration);
        cg_printf(" {%s}\n",
                  disableDestructor ?
                  " if (!hhvm) setAttribute(NoDestructor); " : "");
      }

      if (needsInit) {
        cg_printf("void init();\n");
      }

      // doCall
      if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
        cg_printf("Variant doCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }

      if (classScope->getAttribute(ClassScope::HasInvokeMethod)) {
        FunctionScopePtr func =
          classScope->findFunction(ar, "__invoke", false);
        ASSERT(func);
        if (!func->isAbstract()) {
          cg_printf("const CallInfo *"
                    "t___invokeCallInfoHelper(void *&extra);\n");
        }
      }

      if (classScope->isRedeclaring() &&
          !classScope->derivesFromRedeclaring() &&
          classScope->derivedByDynamic()) {
        cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      {
        std::set<string> done;
        classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
      }
      if (Option::GenerateCPPMacros) {
        classScope->outputCPPJumpTableDecl(cg, ar);
      }
      cg_indentEnd("};\n");

      classScope->outputCPPDynamicClassDecl(cg);

      if (m_stmt) {
        cg.setContext(CodeGenerator::CppClassConstantsDecl);
        m_stmt->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::CppDeclaration);
      }
    }
    break;
  case CodeGenerator::CppImplementation:
    {
      if (m_stmt) {
        cg.setContext(CodeGenerator::CppClassConstantsImpl);
        m_stmt->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::CppImplementation);
      }

      classScope->outputCPPSupportMethodsImpl(cg, ar);

      bool needsInit = classScope->needsInitMethod();
      if (needsInit) {
        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 {
            ClassScopePtr parCls = ar->findClass(m_parent);
            cg_printf("%s%s::init();\n", Option::ClassPrefix,
                      parCls->getId().c_str());
          }
        }
        if (classScope->getVariables()->
            getAttribute(VariableTable::NeedGlobalPointer)) {
          cg.printDeclareGlobals();
        }
        cg.setContext(CodeGenerator::CppInitializer);
        if (m_stmt) m_stmt->outputCPP(cg, ar);

        // This is lame. Exception base class needs to prepare stacktrace
        // outside of its PHP constructor. Every subclass of exception also
        // needs this stacktrace, so we're adding an artificial __init__ in
        // exception.php and calling it here.
        if (m_name == "exception") {
          cg_printf("{CountableHelper h(this); t___init__();}\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";
      std::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->derivesDirectlyFrom(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().c_str());
      }
      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, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      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;
  }
}