Exemplo n.º 1
0
void ReturnStatement::inferTypes(AnalysisResultPtr ar) {
  assert(getFunctionScope().get() == getScope().get());
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());

  FunctionScopePtr funcScope = getFunctionScope();
  if (m_exp) {
    if (funcScope) {
      TypePtr ret;
      if (funcScope->isOverriding()) {
        if (funcScope->getReturnType()) {
          ret = m_exp->inferAndCheck(ar, funcScope->getReturnType(), false);
        } else {
          ConstructPtr self = shared_from_this();
          ret = m_exp->inferAndCheck(ar, Type::Some, false);
        }
      } else {
        ret = m_exp->inferAndCheck(ar, Type::Some, false);
        funcScope->setReturnType(ar, ret);
        funcScope->addRetExprToFix(m_exp);
      }
    } else {
      m_exp->inferAndCheck(ar, Type::Int64, false);
    }
  } else {
    funcScope->setReturnType(ar, TypePtr());
  }
}
Exemplo n.º 2
0
void MethodStatement::inferTypes(AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  if (ar->getPhase() == AnalysisResult::FirstInference && m_stmt) {
    if (m_stmt->hasRetExp() ||
        funcScope->inPseudoMain() ||
        funcScope->getReturnType()) {
      bool lastIsReturn = false;
      if (m_stmt->getCount()) {
        StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1];
        if (lastStmt->is(Statement::KindOfReturnStatement)) {
          lastIsReturn = true;
        }
      }
      if (!lastIsReturn &&
          !(funcScope->inPseudoMain() && !Option::GenerateCPPMain)) {
        ExpressionPtr constant =
          funcScope->inPseudoMain() ? CONSTANT("true") : CONSTANT("null");
        ReturnStatementPtr returnStmt =
          ReturnStatementPtr(new ReturnStatement(getLocation(),
            Statement::KindOfReturnStatement, constant));
        m_stmt->addElement(returnStmt);
      }
    }
  }
  ar->pushScope(funcScope);
  if (m_params) {
    m_params->inferAndCheck(ar, NEW_TYPE(Any), false);
  }
  if (m_stmt) {
    m_stmt->inferTypes(ar);
  }
  ar->popScope();
}
Exemplo n.º 3
0
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce,
                                           FunctionScopePtr func) {
  ConstructPtr self = shared_from_this();
  ar->getDependencyGraph()->add(DependencyGraph::KindOfFunctionCall,
                                ar->getName(), getText(),
                                self, func->getFullName(), func->getStmt());
  TypePtr frt = func->getReturnType();
  if (!frt) {
    m_voidReturn = true;
    setActualType(TypePtr());
    if (!type->is(Type::KindOfAny)) {
      if (!m_allowVoidReturn && ar->isSecondPass() && !func->isAbstract()) {
        ar->getCodeError()->record(self, CodeError::UseVoidReturn, self);
      }
      m_voidWrapper = true;
    }
  } else {
    m_voidReturn = false;
    m_voidWrapper = false;
    type = checkTypesImpl(ar, type, frt, coerce);
  }
  m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
  m_variableArgument = func->isVariableArgument();
  if (m_valid) {
    m_implementedType.reset();
  } else {
    m_implementedType = Type::Variant;
  }

  return type;
}
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce,
                                           FunctionScopePtr func,
                                           bool arrayParams) {
  ConstructPtr self = shared_from_this();
  TypePtr frt = func->getReturnType();
  if (!frt) {
    m_voidReturn = true;
    setActualType(TypePtr());
    if (!type->is(Type::KindOfAny)) {
      if (!m_allowVoidReturn && !func->isFirstPass() && !func->isAbstract()) {
        Compiler::Error(Compiler::UseVoidReturn, self);
      }
      m_voidWrapper = true;
    }
  } else {
    m_voidReturn = false;
    m_voidWrapper = false;
    type = checkTypesImpl(ar, type, frt, coerce);
  }
  if (arrayParams) {
    m_extraArg = 0;
    (*m_params)[0]->inferAndCheck(ar, Type::Array, false);
  } else {
    m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
  }
  m_variableArgument = func->isVariableArgument();
  if (m_valid) {
    m_implementedType.reset();
  } else {
    m_implementedType = Type::Variant;
  }

  return type;
}
Exemplo n.º 5
0
void MethodStatement::outputSwigFFIStub(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  string fname = funcScope->getId();
  string originalName = funcScope->getOriginalName();
  int ac = funcScope->getMaxParamCount();

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

  cg.printf("Variant *%s(HphpSession *s", originalName.c_str());
  ostringstream args;
  bool first = true;
  for (int i = 0; i < ac; i++) {
    cg.printf(", Variant *a%d", i);
    if (first) first = false;
    else args << ", ";
    args << "a" << i;
  }
  if (varArgs) {
    cg.printf(", Variant *va");
    if (!first) args << ", ";
    args << "va";
  }

  if (cg.getContext() == CodeGenerator::SwigFFIDecl) {
    cg.printf(");\n\n");
    return;
  }

  cg.indentBegin(") {\n");
  if (ret) {
    cg.printf("void *result;\n");
    cg.printf("int kind = ");
    cg.printf("%s%s(&result", Option::FFIFnPrefix, fname.c_str());
    if (ac > 0 || varArgs) cg.printf(", ");
  } else {
    cg.printf("%s%s(", Option::FFIFnPrefix, fname.c_str());
  }
  cg.printf("%s);\n", args.str().c_str());
  cg.printf("Variant *ret = ");
  if (ret) {
    cg.printf("hphpBuildVariant(kind, result);\n");
    cg.printf("s->addVariant(ret);\n");
  } else {
    cg.printf("hphpBuildVariant(0, 0);\n");
    cg.printf("s->addVariant(ret);\n");
  }
  cg.printf("return ret;\n");
  cg.indentEnd("}\n\n");
}
Exemplo n.º 6
0
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg,
                                                   AnalysisResultPtr ar,
                                                   const char *cls) {
  if (!m_modifiers->isStatic() || !m_stmt) return;

  CodeGenerator::Context context = cg.getContext();
  FunctionScopePtr funcScope = m_funcScope.lock();

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

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

  m_modifiers->outputCPP(cg, ar);
  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg_printf("void");
  }
  cg_printf(" %s%s(", needsWrapper && !isWrapper ?
            Option::TypedMethodPrefix : Option::MethodPrefix,
            cg.formatLabel(m_name).c_str());
  if (!isWrapper) cg.setContext(CodeGenerator::CppStaticMethodWrapper);
  funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
  cg_printf(") { %s%s%s(", type ? "return " : "",
            needsWrapper && !isWrapper ?
            Option::TypedMethodImplPrefix : Option::MethodImplPrefix,
            cg.formatLabel(m_name).c_str());
  cg_printf("%s%s::s_class_name", Option::ClassPrefix, cls);
  cg.setContext(context);
  if (funcScope->isVariableArgument()) {
    cg_printf(", num_args");
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      ASSERT(param);
      cg_printf(", %s%s", Option::VariablePrefix, param->getName().c_str());
    }
  }
  if (funcScope->isVariableArgument()) {
    cg_printf(", args");
  }
  cg_printf("); }\n");
  if (!isWrapper && needsWrapper) {
    cg.setContext(CodeGenerator::CppTypedParamsWrapperDecl);
    outputCPPStaticMethodWrapper(cg, ar, cls);
    cg.setContext(context);
  }
}
Exemplo n.º 7
0
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce,
                                           FunctionScopePtr func,
                                           bool arrayParams) {
#ifdef HPHP_DETAILED_TYPE_INF_ASSERT
  assert(func->hasUser(getScope(), BlockScope::UseKindCaller));
#endif /* HPHP_DETAILED_TYPE_INF_ASSERT */
  ConstructPtr self = shared_from_this();
  TypePtr frt;
  {
    TRY_LOCK(func);
    func->getInferTypesMutex().assertOwnedBySelf();
    assert(!func->inVisitScopes() || getScope() == func);
    frt = func->getReturnType();
  }
  if (!frt) {
    m_voidReturn = true;
    setActualType(TypePtr());
    if (!isUnused() && !type->is(Type::KindOfAny)) {
      if (!hasContext(ReturnContext) &&
          !func->isFirstPass() && !func->isAbstract()) {
        if (Option::WholeProgram || !func->getContainingClass() ||
            func->isStatic() || func->isFinal() || func->isPrivate()) {
          Compiler::Error(Compiler::UseVoidReturn, self);
        }
      }
      if (!Type::IsMappedToVariant(type)) {
        setExpectedType(type);
      }
      m_voidWrapper = true;
    }
  } else {
    m_voidReturn = false;
    m_voidWrapper = false;
    type = checkTypesImpl(ar, type, frt, coerce);
    assert(m_actualType);
  }
  if (arrayParams) {
    m_extraArg = 0;
    (*m_params)[0]->inferAndCheck(ar, Type::Array, false);
  } else {
    m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
  }
  m_variableArgument = func->isVariableArgument();
  if (m_valid) {
    m_implementedType.reset();
  } else {
    m_implementedType = Type::Variant;
  }
  assert(type);

  return type;
}
Exemplo n.º 8
0
void FunctionContainer::countReturnTypes(
  std::map<std::string, int> &counts,
  const StringToFunctionScopePtrVecMap *redec) {
  for (StringToFunctionScopePtrMap::const_iterator iter =
         m_functions.begin(); iter != m_functions.end(); ++iter) {
    FunctionScopePtr f = iter->second;
    if (f->isLocalRedeclaring()) {
      always_assert(redec);
      for (FunctionScopePtr f: redec->find(iter->first)->second) {
        TypePtr type = f->getReturnType();
        if (type) {
          type->count(counts);
        }
      }
    } else {
      TypePtr type = f->getReturnType();
      if (type) {
        type->count(counts);
      }
    }
  }
}
Exemplo n.º 9
0
void MethodStatement::outputCPPTypeCheckWrapper(CodeGenerator &cg,
                                                AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = getFunctionScope();
  TypePtr type = funcScope->getReturnType();
  bool isMethod = getClassScope();
  string fname = isMethod ? funcScope->getName() : funcScope->getId(cg);

  funcScope->outputCPP(cg, ar);
  cg_printf("%s%s%s(", type ? "return " : "",
            (isMethod ? (m_modifiers->isStatic() ?
                         Option::TypedMethodImplPrefix :
                         Option::TypedMethodPrefix) :
             Option::TypedFunctionPrefix),
            fname.c_str());
  if (getClassScope() && m_modifiers->isStatic()) {
    cg_printf("cls, ");
  }
  if (funcScope->isVariableArgument()) {
    cg_printf("num_args, ");
  }

  assert(m_params);

  for (int i = 0; i < m_params->getCount(); i++) {
    ParameterExpressionPtr param =
      dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
    ASSERT(param);
    if (i) cg_printf(", ");
    cg_printf("%s%s", Option::VariablePrefix,
              param->getName().c_str());
    if (TypePtr spec = funcScope->getParamTypeSpec(i)) {
      if (Type::SameType(spec, funcScope->getParamType(i))) {
        if (spec->is(Type::KindOfArray)) {
          cg_printf(".getArrayData()");
        } else {
          ClassScopePtr cls = ar->findClass(spec->getName());
          assert(cls && !cls->isRedeclaring());
          cg_printf(".getObjectData()");
        }
      }
    }
  }

  if (funcScope->isVariableArgument()) {
    cg_printf(", args");
  }
  cg_printf(");\n");
}
Exemplo n.º 10
0
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");
}
Exemplo n.º 11
0
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg,
                                                   AnalysisResultPtr ar,
                                                   const char *cls) {
  if (!m_modifiers->isStatic() || !m_stmt) return;
  FunctionScopePtr funcScope = m_funcScope.lock();
  ar->pushScope(funcScope);
  m_modifiers->outputCPP(cg, ar);
  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg.printf("void");
  }
  cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str());
  CodeGenerator::Context old = cg.getContext();
  cg.setContext(CodeGenerator::CppStaticMethodWrapper);
  funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
  cg.setContext(old);
  cg.printf(") { %s%s%s(\"%s\"", type ? "return " : "",
            Option::MethodImplPrefix, m_name.c_str(),
            cls);
  if (funcScope->isVariableArgument()) {
    cg.printf(", num_args");
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      ASSERT(param);
      cg.printf(", %s%s", Option::VariablePrefix, param->getName().c_str());
    }
  }
  if (funcScope->isVariableArgument()) {
    cg.printf(", args");
  }
  cg.printf("); }\n");
  ar->popScope();
}
Exemplo n.º 12
0
void MethodStatement::outputJavaFFICPPStub(CodeGenerator &cg,
                                           AnalysisResultPtr ar) {
  // TODO translate PHP namespace once that is supported
  string packageName = Option::JavaFFIRootPackage;

  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  bool inClass = !m_className.empty();
  bool isStatic = !inClass || m_modifiers->isStatic();
  string fname = funcScope->getId();
  int ac = funcScope->getMaxParamCount();
  bool exposeNative = !(ac > 0 || varArgs || !isStatic || !ret && inClass);

  if (inClass && m_modifiers->isAbstract()) {
    // skip all the abstract methods, because hphp doesn't generate code
    // for them
    return;
  }

  if (fname == "__lval" || fname == "__offsetget_lval") return;

  const char *clsName;
  if (inClass) {
    // uses capitalized original class name
    ClassScopePtr cls = ar->findClass(m_className);
    clsName = cls->getOriginalName();
  }
  else {
    clsName = "HphpMain";
  }
  string mangledName = "Java." + packageName + "." + clsName + "." + fname
    + (exposeNative ? "" : "_native");
  // all the existing "_" are replaced as "_1"
  Util::replaceAll(mangledName, "_", "_1");
  Util::replaceAll(mangledName, ".", "_");

  cg.printf("JNIEXPORT %s JNICALL\n", ret ? "jobject" : "void");
  cg.printf("%s(JNIEnv *env, %s target", mangledName.c_str(),
            (isStatic ? "jclass" : "jobject"));

  ostringstream args;
  bool first = true;
  if (!isStatic) {
    // instance method also gets an additional argument, which is a Variant
    // pointer to the target, encoded in int64
    first = false;
    cg.printf(", jlong targetPtr");
    args << "(Variant *)targetPtr";
  }
  for (int i = 0; i < ac; i++) {
    cg.printf(", jlong a%d", i);
    if (first) first = false;
    else args << ", ";
    args << "(Variant *)a" << i;
  }
  if (varArgs) {
    cg.printf(", jlong va");
    if (!first) args << ", ";
    args << "(Variant *)va";
  }

  if (cg.getContext() == CodeGenerator::JavaFFICppDecl) {
    // java_stubs.h
    cg.printf(");\n\n");
    return;
  }

  cg.indentBegin(") {\n");

  // support static/instance methods
  if (ret) {
    cg.printf("void *result;\n");
    cg.printf("int kind = ");
    cg.printf("%s%s%s(&result",
              Option::FFIFnPrefix,
              (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str());
    if (!isStatic || ac > 0 || varArgs) cg.printf(", ");
  }
  else {
    cg.printf("%s%s%s(", Option::FFIFnPrefix,
                         (inClass ? (m_className + "_cls_").c_str() : ""),
                         fname.c_str());
  }
  cg.printf("%s);\n", args.str().c_str());
  if (ret) {
    if (!inClass) {
      // HphpMain extends hphp.Hphp.
      cg.printf("jclass hphp = env->GetSuperclass(target);\n");
    }
    else {
      cg.printf("jclass hphp = env->FindClass(\"hphp/Hphp\");\n");
    }
    cg.printf("return exportVariantToJava(env, hphp, result, kind);\n");
  }

  cg.indentEnd("} /* function */\n\n");
}
Exemplo n.º 13
0
/**
 * Generates the Java stub method for a PHP toplevel function.
 *
 * @author qixin
 */
void MethodStatement::outputJavaFFIStub(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  bool inClass = !m_className.empty();
  bool isStatic = !inClass || m_modifiers->isStatic();
  string fname = funcScope->getId();
  string originalName = funcScope->getOriginalName();
  if (originalName.length() < fname.length()) {
    // if there are functions of the same name, fname may contain "$$..."
    // in the end
    originalName += fname.substr(originalName.length());
  }

  if (originalName == "clone"     || originalName == "equals"
   || originalName == "finalize"  || originalName == "getClass"
   || originalName == "hashCode"  || originalName == "notify"
   || originalName == "notifyAll" || originalName == "toString"
   || originalName == "wait") {
    // not to clash with Java method names
    originalName = "_" + originalName;
  }

  if (cg.getContext() == CodeGenerator::JavaFFIInterface
   || inClass && m_modifiers->isAbstract()) {
    // skip all the abstract methods, because php overriding is not very
    // compatible with Java
    return;
  }

  if (!inClass) printSource(cg);

  // This Java method extracts the Variant pointer from the HphpVariant
  // argument as a 64-bit integer, and then calls the native version.
  bool exposeNative = false;
  int ac = funcScope->getMaxParamCount();
  if (ac > 0 || varArgs || !isStatic || !ret && inClass
   || cg.getContext() == CodeGenerator::JavaFFIInterface) {
    // make methods always return something, so that they can override
    // each other
    cg.printf("public %s%s %s(",
              (isStatic ? "static " : ""),
              (!ret && !inClass ? "void" : "HphpVariant"),
              originalName.c_str());
    ostringstream args;
    bool first = true;
    if (!isStatic) {
      // instance method has an additional parameter
      args << "this.getVariantPtr()";
    }
    for (int i = 0; i < ac; i++) {
      if (first) {
        first = false;
        if (!isStatic) args << ", ";
      }
      else {
        cg.printf(", ");
        args << ", ";
      }
      cg.printf("HphpVariant a%d", i);
      args << "a" << i << ".getVariantPtr()";
    }
    if (varArgs) {
      if (!first) {
        cg.printf(", ");
        args << ", ";
      }
      else if (!isStatic) {
        args << ", ";
      }
      cg.printf("HphpVariant va");
      args << "va.getVariantPtr()";
    }

    if (cg.getContext() == CodeGenerator::JavaFFIInterface) {
      cg.printf(");\n\n");
      return;
    }

    cg.indentBegin(") {\n");
    cg.printf("%s%s_native(%s);\n", (ret ? "return " : ""),
              originalName.c_str(),
              args.str().c_str());
    if (!ret && inClass) {
      cg.printf("return HphpNull.phpNull();\n");
    }
    cg.indentEnd("}\n\n");
  }
  else {
    exposeNative = true;
  }

  // the native method stub
  cg.printf("%s %snative %s %s%s(",
            (exposeNative ? "public" : "private"),
            (isStatic ? "static " : ""), (ret ? "HphpVariant" : "void"),
            originalName.c_str(),
            (exposeNative ? "" : "_native"));
  bool first = true;
  if (!isStatic) {
    // instance method has an additional parameter
    cg.printf("long targetPtr");
    first = false;
  }
  for (int i = 0; i < ac; i++) {
    if (first) first = false;
    else cg.printf(", ");
    cg.printf("long a%d", i);
  }
  if (varArgs) {
    if (!first) cg.printf(", ");
    cg.printf("long va");
  }
  cg.printf(");\n\n");
}
Exemplo n.º 14
0
void MethodStatement::outputHSFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) {
  if (!m_className.empty()) {
    // Haskell currently doesn't support FFI for class methods.
    return;
  }

  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  string fname = funcScope->getId().c_str();
  cg.indentBegin("foreign import ccall \"stubs.h %s%s\" %s%s\n",
                 Option::FFIFnPrefix,
                 fname.c_str(),
                 Option::FFIFnPrefix,
                 fname.c_str());
  cg.printf(":: ");
  if (ret) {
    cg.printf("PtrPtr a -> ");
  }
  int ac = funcScope->getMaxParamCount();
  for (int i = 0; i < ac; ++i) {
    cg.printf("HphpVariantPtr -> ");
  }
  if (varArgs) {
    cg.printf("HphpVariantPtr -> ");
  }
  if (ret) {
    cg.printf("IO CInt");
  } else {
    cg.printf("IO ()");
  }
  cg.indentEnd("\n");

  cg.printf("f_%s :: ", fname.c_str());
  bool first = true;
  if (ac > 0) {
    cg.printf("(");
  }
  for (int i = 0; i < ac; ++i) {
    if (first) {
      first = false;
    } else {
      cg.printf(", ");
    }
    cg.printf("VariantAble a%d", i);
  }
  if (ac > 0) {
    cg.printf(") => ");
  }
  for (int i = 0; i < ac; ++i) {
    cg.printf("a%d -> ", i);
  }
  if (varArgs) {
    cg.printf("[Variant] -> ");
  }
  if (ret) {
    cg.printf("IO Variant");
  } else {
    cg.printf("IO ()");
  }
  cg.printf("\n");
  cg.printf("f_%s ", fname.c_str());
  for (int i = 0; i < ac; ++i) {
    cg.printf("v%d ", i);
  }
  if (varArgs) {
    cg.printf("va ");
  }
  cg.indentBegin("=%s\n", ret ? " alloca (\\pres ->" : "");
  for (int i = 0; i < ac; ++i) {
    cg.indentBegin("withExportedVariant (toVariant v%d) (\\p%d ->\n", i, i);
  }
  if (varArgs) {
    cg.indentBegin("withVParamList va (\\pva ->\n");
  }
  cg.indentBegin("do\n");
  cg.printf("%sffi_%s", ret ? "t <- " : "", fname.c_str());
  if (ret) {
    cg.printf(" pres");
  }
  for (int i = 0; i < ac; ++i) {
    cg.printf(" p%d", i);
  }
  if (varArgs) {
    cg.printf(" pva");
  }
  if (ret) {
    cg.printf("\n");
    cg.printf("ppres <- peek pres\n");
    cg.printf("buildVariant (fromIntegral t) ppres");
  }
  cg.indentEnd(""); // end do
  if (varArgs) {
    cg.indentEnd(")"); // end varargs
  }
  for (int i = 0; i < ac; ++i) {
    cg.indentEnd(")"); // end wEV i
  }
  if (ret) {
    cg.indentEnd(")"); // end alloca
  } else {
    cg.indentEnd("");
  }
  cg.printf("\n");
  return;
}
Exemplo n.º 15
0
void MethodStatement::outputCPPFFIStub(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  bool varArgs = funcScope->isVariableArgument();
  bool ret = funcScope->getReturnType();
  string fname = funcScope->getId();
  bool inClass = !m_className.empty();
  bool isStatic = !inClass || m_modifiers->isStatic();

  if (inClass && m_modifiers->isAbstract()) {
    return;
  }

  if (fname == "__lval" || fname == "__offsetget_lval") {
    return;
  }

  if (ret) {
    cg.printf("int");
  } else {
    cg.printf("void");
  }
  cg.printf(" %s%s%s(", Option::FFIFnPrefix,
            (inClass ? (m_className + "_cls_").c_str() : ""), fname.c_str());
  if (ret) {
    cg.printf("void** res");
  }

  bool first = !ret;

  if (!isStatic) {
    // instance methods need one additional parameter for the target
    if (first) {
      first = false;
    }
    else {
      cg.printf(", ");
    }
    cg.printf("Variant *target");
  }

  int ac = funcScope->getMaxParamCount();
  for (int i = 0; i < ac; ++i) {
    if (first) {
      first = false;
    } else {
      cg.printf(", ");
    }
    cg.printf("Variant *a%d", i);
  }
  if (varArgs) {
    if (!first) {
      cg.printf(", ");
    }
    cg.printf("Variant *va");
  }
  cg.printf(")");
  if (cg.getContext() == CodeGenerator::CppFFIDecl) {
    cg.printf(";\n");
  } else {
    cg.indentBegin(" {\n");
    if (ret) {
      cg.printf("return hphp_ffi_exportVariant(");
    }

    if (!inClass) {
      // simple function call
      cg.printf("%s%s(", Option::FunctionPrefix, fname.c_str());
    }
    else if (isStatic) {
      // static method call
      cg.printf("%s%s::%s%s(", Option::ClassPrefix, m_className.c_str(),
                Option::MethodPrefix, fname.c_str());
    }
    else {
      // instance method call
      cg.printf("dynamic_cast<%s%s *>(target->getObjectData())->",
                Option::ClassPrefix, m_className.c_str());
      cg.printf("%s%s(", Option::MethodPrefix, fname.c_str());
    }

    first = true;
    if (varArgs) {
      cg.printf("%d + (va->isNull() ? 0 : va->getArrayData()->size())", ac);
      first = false;
    }

    for (int i = 0; i < ac; ++i) {
      if (first) {
        first = false;
      } else {
        cg.printf(", ");
      }
      cg.printf("*a%d", i);
    }
    if (varArgs) {
      cg.printf(", va->toArray()");
    }
    if (ret) {
      cg.printf("), res");
    }
    cg.printf(");\n");
    cg.indentEnd("} /* function */\n");
  }
  return;
}
Exemplo n.º 16
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();
}
Exemplo n.º 17
0
void FunctionStatement::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  CodeGenerator::Context context = cg.getContext();

  FunctionScopePtr funcScope = m_funcScope.lock();
  string fname = funcScope->getId(cg).c_str();
  bool pseudoMain = funcScope->inPseudoMain();
  string origFuncName = !pseudoMain ? funcScope->getOriginalName() :
          ("run_init::" + funcScope->getFileScope()->getName());
  string funcSection;

  if (outputFFI(cg, ar)) return;

  if (context == CodeGenerator::NoContext) {
    string rname = cg.formatLabel(m_name);
    if (funcScope->isRedeclaring()) {
      cg.printf("g->%s%s = &%s%s;\n", Option::CallInfoPrefix, m_name.c_str(),
          Option::CallInfoPrefix, fname.c_str());
    }
    if (funcScope->isVolatile()) {
      cg_printf("g->declareFunctionLit(");
      cg_printString(m_name, ar);
      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;
  ar->pushScope(funcScope);

  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);
        ar->popScope();
        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());
  }

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

  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } 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->getFileScope()->pseudoMainName().c_str());
  } else {
    cg_printf(" %s%s(", Option::FunctionPrefix, fname.c_str());
  }

  switch (context) {
  case CodeGenerator::CppForwardDeclaration:
    funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
    cg_printf(");\n");
    if (funcScope->hasDirectInvoke()) {
      cg_printf("Variant %s%s(void *extra, CArrRef params);\n",
                Option::InvokePrefix, fname.c_str());
    }
    break;
  case CodeGenerator::CppDeclaration:
  case CodeGenerator::CppImplementation:
  case CodeGenerator::CppPseudoMain:
    {
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg_indentBegin(") {\n");
      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->getFileScope()->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.setContext(context);
      cg_indentEnd("} /* function */\n");
    }
    break;
  default:
    ASSERT(false);
  }

  ar->popScope();
}
Exemplo n.º 18
0
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce,
                                           FunctionScopePtr func,
                                           bool arrayParams) {
#ifdef HPHP_DETAILED_TYPE_INF_ASSERT
  assert(func->hasUser(getScope(), BlockScope::UseKindCaller));
#endif /* HPHP_DETAILED_TYPE_INF_ASSERT */
  ConstructPtr self = shared_from_this();
  TypePtr frt;
  {
    TRY_LOCK(func);
    func->getInferTypesMutex().assertOwnedBySelf();
    assert(!func->inVisitScopes() || getScope() == func);
    frt = func->getReturnType();
  }

  // fix return type for generators and async functions here, keep the
  // infered return type in function scope to allow further optimizations
  if (func->isGenerator()) {
    frt = Type::GetType(Type::KindOfObject, "Generator");
  } else if (func->isAsync()) {
    frt = Type::GetType(Type::KindOfObject, "WaitHandle");
  }

  m_voidUsed = false;
  if (!frt) {
    m_voidReturn = true;
    setActualType(TypePtr());
    if (!isUnused() && !type->is(Type::KindOfAny)) {
      if (!hasContext(ReturnContext) &&
          !func->isFirstPass() && !func->isAbstract()) {
        if (Option::WholeProgram || !func->getContainingClass() ||
            func->isStatic() || func->isFinal() || func->isPrivate()) {
          m_voidUsed = true;
        }
      }
      if (!Type::IsMappedToVariant(type)) {
        setExpectedType(type);
      }
    }
  } else {
    m_voidReturn = false;
    type = checkTypesImpl(ar, type, frt, coerce);
    assert(m_actualType);
  }
  if (arrayParams) {
    m_extraArg = 0;
    (*m_params)[0]->inferAndCheck(ar, Type::Array, false);
  } else {
    m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
  }
  m_variableArgument = func->allowsVariableArguments();
  if (m_valid) {
    m_implementedType.reset();
  } else {
    m_implementedType = Type::Variant;
  }
  assert(type);

  return type;
}
Exemplo n.º 19
0
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;
  }
}