void MethodStatement::outputCPPStmt(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_stmt) { m_stmt->outputCPP(cg, ar); if (!m_stmt->hasRetExp()) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr cls = ar->getClassScope(); if (funcScope->isConstructor(cls)) { cg.printf("gasInCtor(oldInCtor);\n"); } } } }
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"); }
bool MethodStatement::outputFFI(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr clsScope = ar->getClassScope(); bool pseudoMain = funcScope->inPseudoMain(); bool inClass = !m_className.empty(); // only expose public methods, and ignore those in redeclared classes bool inaccessible = inClass && (!m_modifiers->isPublic() || clsScope->isRedeclaring()); // skip constructors bool isConstructor = inClass && funcScope->isConstructor(clsScope); bool valid = !pseudoMain && !inaccessible && !isConstructor; if (cg.getContext() == CodeGenerator::CppFFIDecl || cg.getContext() == CodeGenerator::CppFFIImpl) { if (valid) outputCPPFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::HsFFI) { if (valid) outputHSFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::JavaFFI || cg.getContext() == CodeGenerator::JavaFFIInterface) { if (valid) outputJavaFFIStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl || cg.getContext() == CodeGenerator::JavaFFICppImpl) { if (valid) outputJavaFFICPPStub(cg, ar); return true; } if (cg.getContext() == CodeGenerator::SwigFFIDecl || cg.getContext() == CodeGenerator::SwigFFIImpl) { if (valid) outputSwigFFIStub(cg, ar); return true; } return false; }
void MethodStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr scope = ar->getClassScope(); string origFuncName; ar->pushScope(funcScope); if (outputFFI(cg, ar)) return; cg.setPHPLineNo(-1); if (cg.getContext() == CodeGenerator::CppImplementation) { printSource(cg); } switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { if (!m_stmt) { cg.printf("// "); } m_modifiers->outputCPP(cg, ar); if (m_name == "__offsetget_lval") { cg.printf("virtual "); } TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } if (m_name == "__lval") { cg.printf(" &___lval("); } else if (m_name == "__offsetget_lval") { cg.printf(" &___offsetget_lval("); } else if (m_modifiers->isStatic() && m_stmt) { // Static method wrappers get generated as support methods cg.printf(" %s%s(const char* cls%s", Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, true); if (m_stmt) { cg.printf(");\n"); } else { cg.printf(") = 0;\n"); } if (funcScope->isConstructor(scope) && !funcScope->isAbstract() && !scope->isInterface()) { funcScope->outputCPPCreateDecl(cg, ar); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { TypePtr type = funcScope->getReturnType(); if (type) { type->outputCPPDecl(cg, ar); } else { cg.printf("void"); } origFuncName = std::string(scope->getOriginalName()) + "::" + m_originalName; if (Option::HotFunctions.find(origFuncName) != Option::HotFunctions.end()) { cg.printf(" __attribute((__section__(\".text.hot\")))"); } else if (Option::ColdFunctions.find(origFuncName) != Option::ColdFunctions.end()) { cg.printf(" __attribute((__section__(\".text.cold\")))"); } if (m_name == "__lval") { cg.printf(" &%s%s::___lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_name == "__offsetget_lval") { cg.printf(" &%s%s::___offsetget_lval(", Option::ClassPrefix, scope->getId().c_str()); } else if (m_modifiers->isStatic()) { cg.printf(" %s%s::%s%s(const char* cls%s", Option::ClassPrefix, scope->getId().c_str(), Option::MethodImplPrefix, m_name.c_str(), funcScope->isVariableArgument() || (m_params && m_params->getCount()) ? ", " : ""); } else { cg.printf(" %s%s::%s%s(", Option::ClassPrefix, scope->getId().c_str(), Option::MethodPrefix, m_name.c_str()); } funcScope->outputCPPParamsDecl(cg, ar, m_params, false); cg.indentBegin(") {\n"); if (m_modifiers->isStatic()) { cg.printf("STATIC_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } else { cg.printf("INSTANCE_METHOD_INJECTION(%s, %s::%s);\n", scope->getOriginalName(), scope->getOriginalName(), m_originalName.c_str()); } if (Option::GenRTTIProfileData && m_params) { for (int i = 0; i < m_params->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); if (param->hasRTTI()) { const string ¶mName = param->getName(); int id = ar->getParamRTTIEntryId(ar->getClassScope(), funcScope, paramName); if (id != -1) { cg.printf("RTTI_INJECTION(%s%s, %d);\n", Option::VariablePrefix, paramName.c_str(), id); } } } } if (m_name == "__lval" || m_name == "__offsetget_lval") { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("Variant &v = %s->__lvalProxy;\n", cg.getOutput() == CodeGenerator::SystemCPP ? "get_system_globals()" : "get_global_variables()"); string lowered = Util::toLower(m_originalName); cg.printf("v = %s%s(%s%s);\n", Option::MethodPrefix, lowered.c_str(), Option::VariablePrefix, param->getName().c_str()); cg.printf("return v;\n"); } else { if (funcScope->isConstructor(scope)) { cg.printf("bool oldInCtor = gasInCtor(true);\n"); } else if (m_name == "__destruct") { cg.printf("setInDtor();\n"); } else if (m_name == "__call") { ParameterExpressionPtr param; if (m_params->getCount() > 0) { param = dynamic_pointer_cast<ParameterExpression>((*m_params)[0]); cg.printf("INCALL_HELPER(%s%s);\n", Option::VariablePrefix, param->getName().c_str()); } else { cg.printf("INCALL_HELPER(\"\");\n"); } } funcScope->outputCPP(cg, ar); cg.setContext(CodeGenerator::NoContext); // no inner functions/classes if (!funcScope->isStatic() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { cg.printf("%sthis = this;\n", Option::VariablePrefix); } outputCPPStmt(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } cg.indentEnd("} /* function */\n"); } break; default: break; } ar->popScope(); }
void 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; } }