void NewObjectExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { string &cname = (m_origName == "self" || m_origName == "parent") ? m_name : m_origName; bool outsideClass = !ar->checkClassPresent(shared_from_this(), m_origName); if (!m_name.empty() && !m_redeclared && m_validClass && !m_dynamic) { ClassScopePtr cls = ar->resolveClass(shared_from_this(), m_name); ASSERT(cls); if (m_receiverTemp.empty()) { if (outsideClass) { cls->outputVolatileCheckBegin(cg, ar, getScope(), cname); } cg_printf("%s%s((NEWOBJ(%s%s)())->create(", Option::SmartPtrPrefix, cls->getId(cg).c_str(), Option::ClassPrefix, cls->getId(cg).c_str()); } else { cg_printf("(%s->create(", m_receiverTemp.c_str()); } FunctionScopePtr dummy; FunctionScope::OutputCPPArguments(m_params, dummy, cg, ar, m_extraArg, m_variableArgument, m_argArrayId, m_argArrayHash, m_argArrayIndex); if (m_receiverTemp.empty()) { cg_printf("))"); if (outsideClass) { cls->outputVolatileCheckEnd(cg); } } else { cg_printf(")"); if (!isUnused()) { cg_printf(", %s", m_receiverTemp.c_str()); } cg_printf(")"); } } else { bool wrap = false; wrap = m_actualType && m_actualType->is(Type::KindOfVariant) && !m_expectedType && !m_implementedType; if (wrap) { cg_printf("((Variant)"); } cg_printf("id(obj%d)", m_objectTemp); if (wrap) { cg_printf(")"); } } }
void ObjectMethodExpression::outputCPPObjectCall(CodeGenerator &cg, AnalysisResultPtr ar) { outputCPPObject(cg, ar); bool isThis = m_object->isThis(); if (!isThis) { if (directVariantProxy(ar) && !m_object->hasCPPTemp()) { if (m_bindClass) { cg_printf(". BIND_CLASS_DOT "); } else { cg_printf("."); } } else { string objType; TypePtr type = m_object->getType(); if (type->isSpecificObject() && !m_name.empty() && m_valid) { objType = type->getName(); ClassScopePtr cls = ar->findClass(objType); objType = cls->getId(cg); } else { objType = "ObjectData"; } if (m_bindClass) { cg_printf("-> BIND_CLASS_ARROW(%s) ", objType.c_str()); } else { cg_printf("->"); } } } else if (m_bindClass && m_classScope) { cg_printf(" BIND_CLASS_ARROW(%s) ", m_classScope->getId(cg).c_str()); } }
void SimpleVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_this) { ASSERT((getContext() & ObjectContext) == 0); if (hasContext(OprLValue) || hasContext(AssignmentLHS)) { cg_printf("throw_assign_this()"); } else if (hasContext(DeepOprLValue) || hasContext(DeepAssignmentLHS) || hasContext(LValue)) { // $this[] op= ...; or $this[] = ... cg_printf("Variant(GET_THIS())"); } else { ClassScopePtr cls = getOriginalClass(); if (cls->derivedByDynamic()) { cg_printf("Object(GET_THIS())"); } else { cg_printf("GET_THIS_TYPED(%s)", cls->getId(cg).c_str()); } } } else if (m_superGlobal) { VariableTablePtr variables = getScope()->getVariables(); string name = variables->getGlobalVariableName(cg, ar, m_name); cg_printf("g->%s", name.c_str()); } else if (m_globals) { cg_printf("get_global_array_wrapper()"); } else { const char *prefix = getScope()->getVariables()->getVariablePrefix(m_sym); cg_printf("%s%s", prefix, cg.formatLabel(m_name).c_str()); } }
void ObjectPropertyExpression::outputCPPValidObject(CodeGenerator &cg, AnalysisResultPtr ar, bool guarded) { TypePtr act; bool close = false; if (!m_object->hasCPPTemp() && m_object->getImplementedType() && !Type::SameType(m_object->getImplementedType(), m_object->getActualType())) { act = m_object->getActualType(); m_object->setActualType(m_object->getImplementedType()); if (guarded) { ClassScopePtr cls = ar->findExactClass(shared_from_this(), act->getName()); cg_printf("((%s%s*)", Option::ClassPrefix, cls->getId().c_str()); close = true; } } m_object->outputCPP(cg, ar); if (act) { if (m_object->getImplementedType()->is(Type::KindOfObject)) { cg_printf(".get()"); } else { cg_printf(".getObjectData%s()", guarded ? "" : "OrNull"); } if (close) cg_printf(")"); m_object->setActualType(act); } else { cg_printf(".get()"); } }
bool ObjectPropertyExpression::outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar, bool noEvalOnError) { if (m_object->isThis()) { if (m_valid) { if (!m_object->getOriginalClass()) { m_valid = false; } else { FunctionScopeRawPtr fs = m_object->getOriginalFunction(); if (!fs || fs->isStatic()) { m_valid = false; } else if (m_object->getOriginalClass() != getClassScope() && m_object->getOriginalClass()->isRedeclaring()) { m_valid = false; } } } if (!m_valid) { cg_printf("GET_THIS_DOT()"); } } else if (m_valid) { TypePtr act; if (!m_object->hasCPPTemp() && m_object->getImplementedType() && !Type::SameType(m_object->getImplementedType(), m_object->getActualType())) { act = m_object->getActualType(); m_object->setActualType(m_object->getImplementedType()); ClassScopePtr cls = ar->findExactClass(shared_from_this(), act->getName()); cg_printf("((%s%s*)", Option::ClassPrefix, cls->getId(cg).c_str()); } m_object->outputCPP(cg, ar); if (act) { if (m_object->getImplementedType()->is(Type::KindOfObject)) { cg_printf(".get())"); } else { cg_printf(".getObjectData())"); } m_object->setActualType(act); } cg_printf("->"); } else { TypePtr t = m_object->getType(); bool ok = t && (t->is(Type::KindOfObject) || t->is(Type::KindOfVariant)); if (noEvalOnError && !ok) { if (!t || !t->is(Type::KindOfArray)) { cg_printf("("); if (m_object->outputCPPUnneeded(cg, ar)) cg_printf(", "); return true; } } ok = ok || !t; if (!ok) cg_printf("Variant("); m_object->outputCPP(cg, ar); if (!ok) cg_printf(")"); cg_printf("."); } return false; }
void NewObjectExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { string &cname = isSelf() || isParent() ? m_name : m_origName; bool outsideClass = !isPresent(); if (!m_name.empty() && m_classScope && !m_dynamic) { ClassScopePtr cls = m_classScope; const string& lClassName = cls->getId(); bool skipCreate = cls->canSkipCreateMethod(); if (m_receiverTemp.empty()) { if (outsideClass) { cls->outputVolatileCheckBegin(cg, ar, getScope(), cname); } cg_printf("%s%s(((%s%s*)%s%s())%s", Option::SmartPtrPrefix, lClassName.c_str(), Option::ClassPrefix, lClassName.c_str(), Option::CreateObjectOnlyPrefix, lClassName.c_str(), skipCreate ? "" : "->create("); } else { cg_printf("((%s%s*)%s.get()%s", Option::ClassPrefix, lClassName.c_str(), m_receiverTemp.c_str(), skipCreate ? "" : "->create("); } if (skipCreate) { ASSERT(!m_params || m_params->getOutputCount() == 0); } else { FunctionScope::OutputCPPArguments(m_params, m_funcScope, cg, ar, m_extraArg, m_variableArgument, m_argArrayId, m_argArrayHash, m_argArrayIndex); } if (m_receiverTemp.empty()) { cg_printf(skipCreate ? ")" : "))"); if (outsideClass) { cls->outputVolatileCheckEnd(cg); } } else { if (!skipCreate) cg_printf(")"); if (!isUnused()) { cg_printf(", %s", m_receiverTemp.c_str()); } cg_printf(")"); } } else { bool wrap = false; wrap = m_actualType && m_actualType->is(Type::KindOfVariant) && !m_expectedType && !m_implementedType; if (wrap) { cg_printf("((Variant)"); } cg_printf("id(obj%d)", m_objectTemp); if (wrap) { cg_printf(")"); } } }
void ClassStatement::outputJavaFFICPPCreator(CodeGenerator &cg, AnalysisResultPtr ar, FunctionScopePtr cons) { ClassScopePtr cls = m_classScope.lock(); string packageName = Option::JavaFFIRootPackage; int ac = cons ? cons->getMaxParamCount() : 0; bool varArgs = cons && cons->isVariableArgument(); const char *clsName = getOriginalName().c_str(); string mangledName = "Java_" + packageName + "_" + clsName + "_create"; Util::replaceAll(mangledName, ".", "_"); cg.printf("JNIEXPORT jlong JNICALL\n"); cg.printf("%s(JNIEnv *env, jclass cls", mangledName.c_str()); ostringstream args; bool first = true; if (varArgs) { args << ac << " + (((Variant *)va)->isNull() ? 0" << " : ((Variant *)va)->getArrayData()->size())"; first = false; } for (int i = 0; i < ac; i++) { if (first) first = false; else { args << ", "; } cg.printf(", jlong a%d", i); args << "*(Variant *)a" << i; } if (varArgs) { if (!first) { args << ", "; } cg.printf(", jlong va"); args << "((Variant *)va)->toArray()"; } if (cg.getContext() == CodeGenerator::JavaFFICppDecl) { // java_stubs.h cg.printf(");\n\n"); return; } cg.indentBegin(") {\n"); cg.printf("ObjectData *obj = "); cg.printf("(NEW(%s%s)())->create(%s);\n", Option::ClassPrefix, cls->getId().c_str(), args.str().c_str()); cg.printf("obj->incRefCount();\n"); cg.printf("return (jlong)(NEW(Variant)(obj));\n"); cg.indentEnd("}\n\n"); }
void 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"); } } }
void ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar) { const char *prefix = Option::ConstantPrefix; string classId; const char *fmt = "Variant %s%s%s;\n"; ClassScopePtr scope = ar->getClassScope(); if (scope) { prefix = Option::ClassConstantPrefix; classId = scope->getId(); fmt = "Variant %s%s_%s;\n"; } for (StringToConstructPtrMap::const_iterator iter = m_declarations.begin(); iter != m_declarations.end(); ++iter) { const string &name = iter->first; if (isDynamic(name)) { cg.printf(fmt, prefix, classId.c_str(), name.c_str()); } } }
void ConstantTable::outputCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar) { const char *prefix = Option::ConstantPrefix; string classId; const char *fmt = "Variant %s%s%s;\n"; ClassScopePtr scope = ar->getClassScope(); if (scope) { prefix = Option::ClassConstantPrefix; classId = scope->getId(cg); fmt = "Variant %s%s_%s;\n"; } for (StringToSymbolMap::iterator iter = m_symbolMap.begin(), end = m_symbolMap.end(); iter != end; ++iter) { Symbol *sym = &iter->second; if (sym->declarationSet() && sym->isDynamic()) { cg_printf(fmt, prefix, classId.c_str(), cg.formatLabel(sym->getName()).c_str()); } } }
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 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())); } } }
void ClassVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr scope = ar->getClassScope(); bool derivFromRedec = scope->derivesFromRedeclaring() && !m_modifiers->isPrivate(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; SimpleVariablePtr var; TypePtr type; switch (cg.getContext()) { case CodeGenerator::CppConstructor: if (m_modifiers->isStatic()) continue; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); value->outputCPPBegin(cg, ar); if (derivFromRedec) { cg_printf("%sset(\"%s\",-1, ", Option::ObjectPrefix, var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(")"); } else { cg_printf("%s%s = ", Option::PropertyPrefix, var->getName().c_str()); value->outputCPP(cg, ar); } cg_printf(";\n"); value->outputCPPEnd(cg, ar); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); if (derivFromRedec) { cg_printf("%sset(\"%s\",-1, null);\n", Option::ObjectPrefix, var->getName().c_str()); } else { type = scope->getVariables()->getFinalType(var->getName()); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf("%s%s = %s;\n", Option::PropertyPrefix, var->getName().c_str(), initializer); } } } break; case CodeGenerator::CppStaticInitializer: { if (!m_modifiers->isStatic()) continue; VariableTablePtr variables = scope->getVariables(); if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable> (assignment->getVariable()); ExpressionPtr value = assignment->getValue(); if (value->containsDynamicConstant(ar)) continue; cg_printf("g->%s%s%s%s = ", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); value->outputCPP(cg, ar); } else { var = dynamic_pointer_cast<SimpleVariable>(exp); type = scope->getVariables()->getFinalType(var->getName()); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf("g->%s%s%s%s = %s", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), initializer); } } cg_printf(";\n"); } break; case CodeGenerator::CppLazyStaticInitializer: { if (!m_modifiers->isStatic()) continue; if (!exp->is(Expression::KindOfAssignmentExpression)) continue; VariableTablePtr variables = scope->getVariables(); AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); if (!value->containsDynamicConstant(ar)) continue; value->outputCPPBegin(cg, ar); cg_printf("g->%s%s%s%s = ", Option::StaticPropertyPrefix, scope->getId(cg).c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(";\n"); value->outputCPPEnd(cg, ar); } break; default: break; } } }
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 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 FunctionScope::outputCPPDynamicInvoke(CodeGenerator &cg, AnalysisResultPtr ar, const char *funcPrefix, const char *name, bool voidWrapperOff /* = false */, bool fewArgs /* = false */, bool ret /* = true */, const char *extraArg /* = NULL */, bool constructor /* = false */) { const char *voidWrapper = (m_returnType || voidWrapperOff) ? "" : ", null"; const char *retrn = ret ? "return " : ""; int maxParam = fewArgs && m_maxParam > Option::InvokeFewArgsCount ? Option::InvokeFewArgsCount : m_maxParam; bool variable = isVariableArgument(); ASSERT(m_minParam >= 0); bool guarded = outputCPPInvokeArgCountCheck(cg, ar, ret, constructor); bool do_while = !ret && !fewArgs && maxParam > m_minParam; if (!fewArgs && maxParam) { for (int i = 0; i < maxParam; i++) { if (isRefParam(i)) { cg_printf("const_cast<Array&>(params).escalate(true);\n"); break; } } if (do_while) cg_printf("do "); cg_indentBegin("{\n"); cg_printf("ArrayData *ad(params.get());\n"); cg_printf("ssize_t pos = ad ? ad->iter_begin() : " "ArrayData::invalid_index;\n"); for (int i = 0; i < m_minParam; i++) { cg_printf("CVarRef arg%d(", i); if (!guarded) cg_printf("count <= %d ? null_variant : ", i); cg_printf("%s(ad->getValue%s(pos%s)));\n", isRefParam(i) ? "ref" : "", isRefParam(i) ? "Ref" : "", i ? " = ad->iter_advance(pos)" : ""); } } if (variable || getOptionalParamCount()) { if (!fewArgs || m_minParam < Option::InvokeFewArgsCount) { cg_printf("if (count <= %d) ", m_minParam); if (do_while) cg_indentBegin("{\n"); } } stringstream callss; callss << retrn << (m_refReturn ? "ref(" : "("); if (m_perfectVirtual) { ClassScopePtr cls = ar->getClassScope(); callss << Option::ClassPrefix << cls->getId(cg) << "::"; } callss << funcPrefix << name << "("; if (extraArg) { callss << extraArg; if (variable) { callss << ","; } } if (variable) { callss << "count"; } bool preArgs = variable || extraArg; string call = callss.str(); cg_printf("%s", call.c_str()); for (int i = 0; i < m_minParam; i++) { if (preArgs || i > 0) cg_printf(", "); if (isRefParam(i)) { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("ref(a%d)", i); } else { cg_printf("null_variant"); } } else { cg_printf("arg%d", i); } } else { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("a%d", i); } else { cg_printf("null"); } } else { cg_printf("arg%d", i); } } } cg_printf(")%s);\n", voidWrapper); for (int iMax = m_minParam; iMax < maxParam; ) { if (!ret) { if (do_while) { cg_printf("break;\n"); cg_indentEnd("}\n"); } else { cg_printf("else "); } } if (!fewArgs) { cg_printf("CVarRef arg%d(%s(ad->getValue%s(pos%s)));\n", iMax, isRefParam(iMax) ? "ref" : "", isRefParam(iMax) ? "Ref" : "", iMax ? " = ad->iter_advance(pos)" : ""); } if (++iMax < maxParam || variable) { cg_printf("if (count == %d) ", iMax); if (do_while) cg_indentBegin("{\n"); } cg_printf("%s", call.c_str()); for (int i = 0; i < iMax; i++) { if (preArgs || i > 0) cg_printf(", "); if (isRefParam(i)) { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("ref(a%d)", i); } else { cg_printf("null_variant"); } } else { cg_printf("arg%d", i); } } else { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("a%d", i); } else { cg_printf("null_variant"); } } else { cg_printf("arg%d", i); } } } cg_printf(")%s);\n", voidWrapper); } if (variable) { if (do_while) { cg_printf("break;\n"); cg_indentEnd("}\n"); } if (fewArgs) { if (maxParam == Option::InvokeFewArgsCount) return; cg_printf("Array params;\n"); for (int i = maxParam; i < Option::InvokeFewArgsCount; i++) { cg_printf("if (count >= %d) params.append(a%d);\n", i + 1, i); } } cg_printf("%s,", call.c_str()); for (int i = 0; i < maxParam; i++) { if (isRefParam(i)) { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("ref(a%d), ", i); } else { cg_printf("null_variant, "); } } else { cg_printf("ref(arg%d), ", i); } } else { if (fewArgs) { if (i < Option::InvokeFewArgsCount) { cg_printf("a%d, ", i); } else { cg_printf("null_variant, "); } } else { cg_printf("arg%d, ", i); } } } if (fewArgs) { cg_printf("params)%s);\n", voidWrapper); } else { cg_printf("params.slice(%d, count - %d, false))%s);\n", maxParam, maxParam, voidWrapper); } } if (!fewArgs && maxParam) { if (do_while) { cg_indentEnd("} while (false);\n"); } else { cg_indentEnd("}\n"); } } }
bool DynamicFunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { bool nonStatic = !m_class && m_className.empty(); if (!nonStatic && !m_class && !m_validClass && !m_redeclared) return FunctionCall::preOutputCPP(cg, ar, state); // Short circuit out if inExpression() returns false if (!ar->inExpression()) return true; if (m_class) { m_class->preOutputCPP(cg, ar, state); } m_nameExp->preOutputCPP(cg, ar, state); ar->wrapExpressionBegin(cg); m_ciTemp = cg.createNewId(shared_from_this()); bool lsb = false; ClassScopePtr cls; if (m_validClass) { cls = ar->findClass(m_className); } if (!m_classScope && !m_className.empty() && m_cppTemp.empty() && m_origClassName != "self" && m_origClassName != "parent" && m_origClassName != "static") { // Create a temporary to hold the class name, in case it is not a // StaticString. m_clsNameTemp = cg.createNewId(shared_from_this()); cg_printf("CStrRef clsName%d(", m_clsNameTemp); cg_printString(m_origClassName, ar, shared_from_this()); cg_printf(");\n"); } if (nonStatic) { cg_printf("const CallInfo *cit%d;\n", m_ciTemp); cg_printf("void *vt%d;\n", m_ciTemp); cg_printf("get_call_info_or_fail(cit%d, vt%d, ", m_ciTemp, m_ciTemp); } else { cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp); if (m_class) { if (m_class->is(KindOfScalarExpression)) { ASSERT(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)-> getString().c_str(), "static") == 0); cg_printf("mcp%d.staticMethodCall(", m_ciTemp); cg_printf("\"static\""); lsb = true; } else { cg_printf("mcp%d.dynamicNamedCall(", m_ciTemp); m_class->outputCPP(cg, ar); } cg_printf(", "); } else if (m_validClass) { cg_printf("mcp%d.staticMethodCall(\"%s\", ", m_ciTemp, cls->getId(cg).c_str()); } else { cg_printf("mcp%d.staticMethodCall(\"%s\", ", m_ciTemp, m_className.c_str()); } } if (m_nameExp->is(Expression::KindOfSimpleVariable)) { m_nameExp->outputCPP(cg, ar); } else { cg_printf("("); m_nameExp->outputCPP(cg, ar); cg_printf(")"); } if (!nonStatic) { cg_printf(");\n"); if (lsb) cg_printf("mcp%d.lateStaticBind(info);\n"); cg_printf("const CallInfo *&cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp); if (m_validClass) { cg_printf("%s%s::%sget_call_info(mcp%d", Option::ClassPrefix, cls->getId(cg).c_str(), Option::ObjectStaticPrefix, m_ciTemp, m_className.c_str()); } else if (m_redeclared) { cg_printf("g->%s%s->%sget_call_info(mcp%d", Option::ClassStaticsObjectPrefix, m_className.c_str(), Option::ObjectStaticPrefix, m_ciTemp, m_className.c_str()); } } if (nonStatic || !m_class) { cg_printf(");\n"); } if (m_params && m_params->getCount() > 0) { ar->pushCallInfo(m_ciTemp); m_params->preOutputCPP(cg, ar, state); ar->popCallInfo(); } ar->pushCallInfo(m_ciTemp); preOutputStash(cg, ar, state); ar->popCallInfo(); if (!(state & FixOrder)) { cg_printf("id(%s);\n", cppTemp().c_str()); } return true; }
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool lazyInit = cg.getContext() == CodeGenerator::CppLazyStaticInitializer; if (cg.getContext() != CodeGenerator::CppClassConstantsDecl && cg.getContext() != CodeGenerator::CppClassConstantsImpl && !lazyInit) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_exp->getCount(); i++) { AssignmentExpressionPtr exp = dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]); ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp->getVariable()); TypePtr type = scope->getConstants()->getFinalType(var->getName()); ExpressionPtr value = exp->getValue(); if (!scope->getConstants()->isDynamic(var->getName()) == lazyInit) { continue; } switch (cg.getContext()) { case CodeGenerator::CppClassConstantsDecl: cg_printf("extern const "); if (type->is(Type::KindOfString)) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s_%s;\n", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); break; case CodeGenerator::CppClassConstantsImpl: { cg_printf("const "); bool isString = type->is(Type::KindOfString); if (isString) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } value->outputCPPBegin(cg, ar); cg_printf(" %s%s_%s", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); cg_printf(isString ? "(" : " = "); ScalarExpressionPtr scalarExp = dynamic_pointer_cast<ScalarExpression>(value); if (isString && scalarExp) { cg_printf("LITSTR_INIT(%s)", scalarExp->getCPPLiteralString(cg).c_str()); } else { value->outputCPP(cg, ar); } cg_printf(isString ? ");\n" : ";\n"); value->outputCPPEnd(cg, ar); break; } case CodeGenerator::CppLazyStaticInitializer: value->outputCPPBegin(cg, ar); cg_printf("g->%s%s_%s = ", Option::ClassConstantPrefix, scope->getId(cg).c_str(), var->getName().c_str()); value->outputCPP(cg, ar); cg_printf(";\n"); value->outputCPPEnd(cg, ar); break; default: ASSERT(false); } } }
void SimpleVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { VariableTablePtr variables = getScope()->getVariables(); if (m_this) { ASSERT((getContext() & ObjectContext) == 0); if (hasContext(OprLValue) || hasContext(AssignmentLHS)) { cg_printf("throw_assign_this()"); return; } if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) { ASSERT(m_sym); const string &namePrefix = getNamePrefix(); cg_printf("%s%sthis", namePrefix.c_str(), variables->getVariablePrefix(m_sym)); } else if (hasContext(DeepOprLValue) || hasContext(DeepAssignmentLHS) || hasContext(LValue)) { // $this[] op= ...; or $this[] = ... cg_printf("Variant(GET_THIS())"); } else { ClassScopePtr cls = getOriginalClass(); if (!cls || cls->derivedByDynamic()) { cg_printf("Object(GET_THIS())"); } else { cg_printf("GET_THIS_TYPED(%s)", cls->getId().c_str()); } } } else if (m_superGlobal) { const string &name = variables->getGlobalVariableName(ar, m_name); cg_printf("g->%s", name.c_str()); } else if (m_globals) { cg_printf("get_global_array_wrapper()"); } else { ASSERT(m_sym); bool sw = false; if (m_sym->isShrinkWrapped() && m_context == Declaration) { ASSERT(!getFunctionScope()->isGenerator()); TypePtr type = m_sym->getFinalType(); type->outputCPPDecl(cg, ar, getScope()); sw = true; cg_printf(" "); } const string &prefix0 = getNamePrefix(); const char *prefix1 = variables->getVariablePrefix(m_sym); cg_printf("%s%s%s", prefix0.c_str(), prefix1, CodeGenerator::FormatLabel(m_name).c_str()); if (m_originalSym) { cg.printf(" /* %s */", m_originalSym->getName().c_str()); } if (sw) { TypePtr type = m_sym->getFinalType(); const char *initializer = type->getCPPInitializer(); if (initializer) { cg_printf(" = %s", initializer); } } } }
void ClassStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopePtr classScope = m_classScope.lock(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isRedeclaring()) { cg.printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n", Option::ClassStaticsObjectPrefix, m_name.c_str(), Option::ClassStaticsPrefix, classScope->getId().c_str()); } if (classScope->isVolatile()) { cg.printf("g->declareClass(\"%s\");\n", m_name.c_str()); } return; } if (cg.getContext() != CodeGenerator::CppForwardDeclaration) { printSource(cg); } ar->pushScope(classScope); string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); bool redeclared = classScope->isRedeclaring(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { cg.printf("FORWARD_DECLARE_CLASS(%s)\n", clsName); if (redeclared) { cg.printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName); } } if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsDecl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppForwardDeclaration); } break; case CodeGenerator::CppDeclaration: { ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); cg.printf("class %s%s", Option::ClassPrefix, clsName); bool derived = false; if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)) { if (parCls->isRedeclaring()) { cg.printf(" : public DynamicObjectData"); } else { cg.printf(" : virtual public %s%s", Option::ClassPrefix, parCls->getId().c_str()); } derived = true; } if (m_base) { 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)) { // temporary fix for inheriting from a re-declaring class string id = intfClassScope->getId(); if (!derived) { derived = true; cg.printf(" :"); } else { cg.printf(","); } cg.printf(" virtual public %s%s", Option::ClassPrefix, id.c_str()); } } } if (!derived) { const char *op = derived ? "," : " :"; if (classScope->derivesFromRedeclaring()) { cg.printf("%s public DynamicObjectData", op); } else { cg.printf("%s virtual public ObjectData", op); } } cg.indentBegin(" {\n"); if (Option::GenerateCPPMacros) { vector<string> bases; getAllParents(ar, bases); cg.indentBegin("BEGIN_CLASS_MAP(%s)\n", clsName); for (unsigned int i = 0; i < bases.size(); i++) { cg.printf("PARENT_CLASS(%s)\n", bases[i].c_str()); } cg.indentEnd("END_CLASS_MAP(%s)\n", clsName); } if (Option::GenerateCPPMacros) { bool dyn = classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared; bool idyn = classScope->derivesFromRedeclaring() == ClassScope::IndirectFromRedeclared; bool redec = classScope->isRedeclaring(); if (!classScope->derivesFromRedeclaring()) { cg.printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, m_originalName.c_str(), m_parent.empty() ? "ObjectData" : m_parent.c_str()); } else { cg.printf("DECLARE_DYNAMIC_CLASS(%s, %s)\n", clsName, m_originalName.c_str()); } if (cg.getOutput() == CodeGenerator::SystemCPP || Option::EnableEval >= Option::LimitedEval) { cg.printf("DECLARE_INVOKES_FROM_EVAL\n"); } if (dyn || idyn || redec) { if (redec) { cg.indentBegin("Variant %sroot_invoke(const char* s, CArrRef ps, " "int64 h, bool f = true) {\n", Option::ObjectPrefix); cg.printf("return root->%sinvoke(s, ps, h, f);\n", Option::ObjectPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sroot_invoke_few_args(const char* s, " "int64 h, int count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", CVarRef a%d = null_variant", i); } cg.printf(") {\n"); cg.printf("return root->%sinvoke_few_args(s, h, count", Option::ObjectPrefix); for (int i = 0; i < Option::InvokeFewArgsCount; i++) { cg.printf(", a%d", i); } cg.printf(");\n"); cg.indentEnd("}\n"); if (!dyn && !idyn) cg.printf("private: ObjectData* root;\n"); cg.printf("public:\n"); } string conInit = ":"; if (dyn) { conInit += "DynamicObjectData(\"" + m_parent + "\", r)"; } else if (idyn) { conInit += string(Option::ClassPrefix) + parCls->getId() + "(r?r:this)"; } else { conInit += "root(r?r:this)"; } cg.printf("%s%s(ObjectData* r = NULL)%s {}\n", Option::ClassPrefix, clsName, conInit.c_str()); } } cg.printf("void init();\n", Option::ClassPrefix, clsName); if (classScope->needLazyStaticInitializer()) { cg.printf("static GlobalVariables *lazy_initializer" "(GlobalVariables *g);\n"); } if (!classScope->derivesFromRedeclaring()){ classScope->getVariables()->outputCPPPropertyDecl(cg, ar); } 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"); } 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 %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(%s%s(NEW(%s%s)(root))->" "dynCreate(params, init));\n", Option::SmartPtrPrefix, clsName, Option::ClassPrefix, clsName); cg.indentEnd("}\n"); cg.indentBegin("Variant %sconstant(const char* s) {\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentBegin("Variant %sinvoke_from_eval(const char *c, " "const char *s, Eval::VariableEnvironment &env, " "const Eval::FunctionCallExpression *call, " "int64 hash = -1, bool fatal = true) " "{\n", Option::ObjectStaticPrefix); cg.printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, " "fatal);\n", Option::ClassPrefix, clsName, Option::ObjectStaticPrefix); cg.indentEnd("}\n"); cg.indentEnd("};\n"); } } break; case CodeGenerator::CppImplementation: if (m_stmt) { cg.setContext(CodeGenerator::CppClassConstantsImpl); m_stmt->outputCPP(cg, ar); cg.setContext(CodeGenerator::CppImplementation); } classScope->outputCPPSupportMethodsImpl(cg, ar); if (redeclared) { cg.printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n", Option::ClassStaticsPrefix, clsName); } cg.indentBegin("void %s%s::init() {\n", Option::ClassPrefix, clsName); if (!m_parent.empty()) { if (classScope->derivesFromRedeclaring() == ClassScope::DirectFromRedeclared) { cg.printf("parent->init();\n"); } else { cg.printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str()); } } cg.setContext(CodeGenerator::CppConstructor); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); if (classScope->needStaticInitializer()) { cg.indentBegin("void %s%s::os_static_initializer() {\n", Option::ClassPrefix, clsName); cg.printDeclareGlobals(); cg.setContext(CodeGenerator::CppStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.indentBegin("void %s%s() {\n", Option::ClassStaticInitializerPrefix, clsName); cg.printf("%s%s::os_static_initializer();\n", Option::ClassPrefix, clsName); cg.indentEnd("}\n"); } if (classScope->needLazyStaticInitializer()) { cg.indentBegin("GlobalVariables *%s%s::lazy_initializer(" "GlobalVariables *g) {\n", Option::ClassPrefix, clsName); cg.indentBegin("if (!g->%s%s) {\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix, clsName); cg.setContext(CodeGenerator::CppLazyStaticInitializer); if (m_stmt) m_stmt->outputCPP(cg, ar); cg.indentEnd("}\n"); cg.printf("return g;\n"); cg.indentEnd("}\n"); } cg.setContext(CodeGenerator::CppImplementation); if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: if (m_stmt) m_stmt->outputCPP(cg, ar); break; case CodeGenerator::JavaFFI: { if (classScope->isRedeclaring()) break; // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class // also, uses the original capitalized class name string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFI); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); printSource(cgCls); string clsModifier; switch (m_type) { case T_CLASS: break; case T_ABSTRACT: clsModifier = "abstract "; break; case T_FINAL: clsModifier = "final "; break; } cgCls.printf("public %sclass %s ", clsModifier.c_str(), getOriginalName().c_str()); ClassScopePtr parCls; if (!m_parent.empty()) parCls = ar->findClass(m_parent); if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent) && parCls->isUserClass() && !parCls->isRedeclaring()) { // system classes are not supported in static FFI translation // they shouldn't appear as superclasses as well cgCls.printf("extends %s", parCls->getOriginalName()); } else { cgCls.printf("extends HphpObject"); } if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" implements "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName()); } } } cgCls.indentBegin(" {\n"); // constructor for initializing the variant pointer cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n", getOriginalName().c_str()); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { // if not an abstract class and not having an explicit constructor, // adds a default constructor outputJavaFFIConstructor(cgCls, ar, cons); } if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: { if (classScope->isRedeclaring()) break; if (m_stmt) m_stmt->outputCPP(cg, ar); FunctionScopePtr cons = classScope->findConstructor(ar, true); if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) { outputJavaFFICPPCreator(cg, ar, cons); } } break; default: ASSERT(false); break; } ar->popScope(); }
void 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; } }
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isVolatile()) { const vector<string> &bases = classScope->getBases(); for (unsigned i = 0; i < bases.size(); ++i) { const string &name = bases[i]; if (cg.checkHoistedClass(name) || classScope->hasKnownBase(i)) { continue; } ClassScopePtr base = ar->findClass(name); if (base && base->isVolatile()) { cg_printf("checkClassExistsThrow("); cg_printString(name, ar, shared_from_this()); cg_printf(", &%s->CDEC(%s));\n", cg.getGlobals(ar), CodeGenerator::FormatLabel(base->getName()).c_str()); } } classScope->outputCPPDef(cg); cg.addHoistedClass(m_name); } return; } string clsNameStr = classScope->getId(); const char *clsName = clsNameStr.c_str(); switch (cg.getContext()) { case CodeGenerator::CppDeclaration: { printSource(cg); if (Option::GenerateCPPMacros) { classScope->outputForwardDeclaration(cg); } if (classScope->isRedeclaring()) { classScope->outputCPPGlobalTableWrappersDecl(cg, ar); } cg_printf("class %s%s", Option::ClassPrefix, clsName); if (m_base && Option::UseVirtualDispatch && !classScope->isRedeclaring()) { const char *sep = " :"; 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)) { string id = intfClassScope->getId(); cg_printf("%s public %s%s", sep, Option::ClassPrefix, id.c_str()); sep = ","; } } } cg_indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cg, ar); bool hasPropTable = classScope->checkHasPropTable(ar); if (hasPropTable) { cg_printf("public: static const ClassPropTable %sprop_table;\n", Option::ObjectStaticPrefix); } cg_indentEnd("};\n"); if (hasPropTable) { classScope->outputCPPGlobalTableWrappersDecl(cg, ar); } 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); } cg.addClass(getClassScope()->getName(), getClassScope()); if (classScope->isRedeclaring() || classScope->checkHasPropTable(ar)) { classScope->outputCPPGlobalTableWrappersImpl(cg, ar); } } break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: // do nothing break; case CodeGenerator::JavaFFI: { // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class string clsFile = outputDir + getOriginalName() + ".java"; std::ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFIInterface); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); cgCls.printf("public interface %s", getOriginalName().c_str()); if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" extends "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName().c_str()); } } } cgCls.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: // do nothing break; default: ASSERT(false); break; } }
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (cg.getContext() == CodeGenerator::NoContext) { if (classScope->isVolatile()) { cg_printf("g->CDEC(%s) = true;\n", cg.formatLabel(m_name).c_str()); } return; } string clsNameStr = classScope->getId(cg); const char *clsName = clsNameStr.c_str(); switch (cg.getContext()) { case CodeGenerator::CppForwardDeclaration: if (Option::GenerateCPPMacros) { if (!Option::UseVirtualDispatch || classScope->isRedeclaring()) { cg_printf("FORWARD_DECLARE_GENERIC_INTERFACE(%s);\n", clsName); } else { cg_printf("FORWARD_DECLARE_INTERFACE(%s);\n", clsName); } } break; case CodeGenerator::CppDeclaration: { printSource(cg); cg_printf("class %s%s", Option::ClassPrefix, clsName); if (m_base && Option::UseVirtualDispatch && !classScope->isRedeclaring()) { const char *sep = " :"; 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)) { string id = intfClassScope->getId(cg); cg_printf("%s public %s%s", sep, Option::ClassPrefix, id.c_str()); sep = ","; } } } cg_indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cg, ar); cg_indentEnd("};\n"); } break; case CodeGenerator::CppImplementation: // do nothing break; case CodeGenerator::CppFFIDecl: case CodeGenerator::CppFFIImpl: // do nothing break; case CodeGenerator::JavaFFI: { // TODO support PHP namespaces, once HPHP supports it string packageName = Option::JavaFFIRootPackage; string packageDir = packageName; Util::replaceAll(packageDir, ".", "/"); string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix + packageDir + "/"; Util::mkdir(outputDir); // uses a different cg to generate a separate file for each PHP class string clsFile = outputDir + getOriginalName() + ".java"; ofstream fcls(clsFile.c_str()); CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP); cgCls.setContext(CodeGenerator::JavaFFIInterface); cgCls.printf("package %s;\n\n", packageName.c_str()); cgCls.printf("import hphp.*;\n\n"); cgCls.printf("public interface %s", getOriginalName().c_str()); if (m_base) { bool first = true; for (int i = 0; i < m_base->getCount(); i++) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>((*m_base)[i]); const char *intf = exp->getString().c_str(); ClassScopePtr intfClassScope = ar->findClass(intf); if (intfClassScope && classScope->derivesFrom(ar, intf, false, false) && intfClassScope->isUserClass()) { if (first) { cgCls.printf(" extends "); first = false; } else { cgCls.printf(", "); } cgCls.printf(intfClassScope->getOriginalName().c_str()); } } } cgCls.indentBegin(" {\n"); if (m_stmt) m_stmt->outputCPP(cgCls, ar); cgCls.indentEnd("}\n"); fcls.close(); } break; case CodeGenerator::JavaFFICppDecl: case CodeGenerator::JavaFFICppImpl: // do nothing break; default: ASSERT(false); break; } }
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar, int doExist) { if (m_valid) { TypePtr type = m_object->getActualType(); if (type->isSpecificObject()) { ClassScopePtr cls(type->getClass(ar, getScope())); if (cls) getFileScope()->addUsedClassFullHeader(cls); } } 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) { if (cg.callInfoTop() != -1) { func += "argval"; } else { func += "get"; } } else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) { if (m_context & UnsetContext) { always_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 && !m_object->isThis() && (!m_object->is(KindOfSimpleVariable) || !static_pointer_cast<SimpleVariable>(m_object)->isGuarded())) { cg_printf("(obj_tmp = "); outputCPPValidObject(cg, ar, false); bool write_context = hasAnyContext(LValue | RefValue | DeepReference | UnsetContext | OprLValue | DeepOprLValue | DeepAssignmentLHS | AssignmentLHS) && !doUnset; cg_printf(", LIKELY(obj_tmp != 0) %s ", write_context ? "||" : "?"); always_assert(m_property->is(KindOfScalarExpression)); ScalarExpressionPtr name = static_pointer_cast<ScalarExpression>(m_property); if (doExist || doUnset) { cg_printf(doUnset ? "unset" : doExist > 0 ? "isset" : "empty"); } ClassScopePtr cls = ar->findExactClass(shared_from_this(), m_object->getActualType()->getName()); if (write_context) { cg_printf("(throw_null_object_prop(),false),"); } cg_printf("(((%s%s*)obj_tmp)->%s%s)", Option::ClassPrefix, cls->getId().c_str(), Option::PropertyPrefix, name->getString().c_str()); if (!write_context) { cg_printf(" : (raise_null_object_prop(),%s)", doUnset ? "null_variant" : doExist ? doExist > 0 ? "false" : "true" : nullName(ar, getCPPType()).c_str()); } cg_printf(")"); return; } if (m_valid && (doExist || doUnset)) { cg_printf(doUnset ? "unset(" : doExist > 0 ? "isset(" : "empty("); } bool flag = outputCPPObject(cg, ar, !m_valid && (doUnset || doExist)); if (flag) { cg_printf("id("); outputCPPProperty(cg, ar); cg_printf(")"); if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true"); cg_printf(")"); } else if (m_valid) { always_assert(m_object->getActualType() && m_object->getActualType()->isSpecificObject()); ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(m_property); cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str()); if (doExist || doUnset) cg_printf(")"); } else { cg_printf("%s(", func.c_str()); if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) { 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 NewObjectExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { string &cname = (m_origName == "self" || m_origName == "parent") ? m_name : m_origName; if (m_name.empty() || m_redeclared || !m_validClass || m_dynamic) { // Short circuit out if inExpression() returns false if (!ar->inExpression()) return true; if (m_nameExp) m_nameExp->preOutputCPP(cg, ar, state); ar->wrapExpressionBegin(cg); m_ciTemp = cg.createNewId(ar); m_objectTemp = cg.createNewId(ar); cg_printf("Object obj%d(", m_objectTemp); if (m_redeclared) { bool outsideClass = !ar->checkClassPresent(m_origName); ClassScopePtr cls = ar->resolveClass(m_name); ASSERT(cls); if (outsideClass) { cls->outputVolatileCheckBegin(cg, ar, cname); } cg_printf("g->%s%s->createOnly()", Option::ClassStaticsObjectPrefix, m_name.c_str()); if (outsideClass) { cls->outputVolatileCheckEnd(cg); } } else { cg_printf("create_object_only("); if (!cname.empty()) { cg_printf("\"%s\"", cname.c_str()); } else if (m_nameExp->is(Expression::KindOfSimpleVariable)) { m_nameExp->outputCPP(cg, ar); } else { cg_printf("("); m_nameExp->outputCPP(cg, ar); cg_printf(")"); } cg_printf(")"); } cg_printf(");\n"); cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp, m_objectTemp); cg_printf("mcp%d.construct(obj%d);\n", m_ciTemp, m_objectTemp); cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp); if (m_params && m_params->getCount() > 0) { ar->pushCallInfo(m_ciTemp); m_params->preOutputCPP(cg, ar, state); ar->popCallInfo(); } cg_printf("(cit%d->getMeth())(mcp%d, ", m_ciTemp, m_ciTemp); if (m_params && m_params->getOutputCount()) { ar->pushCallInfo(m_ciTemp); FunctionScope::outputCPPArguments(m_params, cg, ar, -1, false); ar->popCallInfo(); } else { cg_printf("Array()"); } cg_printf(");\n"); if (state & FixOrder) { ar->pushCallInfo(m_ciTemp); preOutputStash(cg, ar, state); ar->popCallInfo(); } if (hasCPPTemp() && !(state & FixOrder)) { cg_printf("id(%s);\n", cppTemp().c_str()); } return true; } else { bool tempRcvr = true; bool paramEffect = false; if (m_params && m_params->getCount() > 0) { for (int i = m_params->getCount(); i--; ) { if (!(*m_params)[i]->isScalar()) { paramEffect = true; break; } } } if (!paramEffect) { tempRcvr = false; } if (tempRcvr && ar->inExpression()) { bool outsideClass = !ar->checkClassPresent(m_origName); ClassScopePtr cls = ar->resolveClass(m_name); ASSERT(cls); ar->wrapExpressionBegin(cg); m_receiverTemp = genCPPTemp(cg, ar); cg_printf("%s%s %s = ", Option::SmartPtrPrefix, cls->getId(cg).c_str(), m_receiverTemp.c_str()); if (outsideClass) { cls->outputVolatileCheckBegin(cg, ar, cname); } cg_printf("NEWOBJ(%s%s)()", Option::ClassPrefix, cls->getId(cg).c_str()); if (outsideClass) { cls->outputVolatileCheckEnd(cg); } cg_printf(";\n"); } bool tempParams = FunctionCall::preOutputCPP(cg, ar, state); return tempRcvr || tempParams; } }
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 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 MethodStatement::outputCPPFFIStub(CodeGenerator &cg, AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); ClassScopePtr clsScope = getClassScope(); bool varArgs = funcScope->isVariableArgument(); bool ret = funcScope->getReturnType(); string fname = funcScope->getId(cg); bool inClass = !m_className.empty(); bool isStatic = !inClass || m_modifiers->isStatic(); if (inClass && m_modifiers->isAbstract()) { return; } if (funcScope->getName() == "__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, clsScope->getId(cg).c_str(), Option::MethodPrefix, funcScope->getName().c_str()); } else { // instance method call cg_printf("dynamic_cast<%s%s *>(target->getObjectData())->", Option::ClassPrefix, clsScope->getId(cg).c_str()); cg_printf("%s%s(", Option::MethodPrefix, funcScope->getName().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("}\n"); cg.printImplSplitter(); } return; }
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (cg.getContext() != CodeGenerator::CppClassConstantsDecl && cg.getContext() != CodeGenerator::CppClassConstantsImpl) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_exp->getCount(); i++) { AssignmentExpressionPtr exp = dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]); ConstantExpressionPtr var = dynamic_pointer_cast<ConstantExpression>(exp->getVariable()); TypePtr type = scope->getConstants()->getFinalType(var->getName()); ExpressionPtr value = exp->getValue(); if (scope->getConstants()->isDynamic(var->getName())) { continue; } switch (cg.getContext()) { case CodeGenerator::CppClassConstantsDecl: cg_printf("extern const "); if (type->is(Type::KindOfString)) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } cg_printf(" %s%s%s%s;\n", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); break; case CodeGenerator::CppClassConstantsImpl: { bool isString = type->is(Type::KindOfString); bool isVariant = Type::IsMappedToVariant(type); ScalarExpressionPtr scalarExp = dynamic_pointer_cast<ScalarExpression>(value); bool stringForVariant = false; if (isVariant && scalarExp && scalarExp->getActualType() && scalarExp->getActualType()->is(Type::KindOfString)) { cg_printf("static const StaticString %s%s%s%s%sv(LITSTR_INIT(%s));\n", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), Option::IdPrefix.c_str(), scalarExp->getCPPLiteralString().c_str()); stringForVariant = true; } cg_printf("const "); if (isString) { cg_printf("StaticString"); } else { type->outputCPPDecl(cg, ar, getScope()); } value->outputCPPBegin(cg, ar); cg_printf(" %s%s%s%s", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str()); cg_printf(isString ? "(" : " = "); if (stringForVariant) { cg_printf("%s%s%s%s%sv", Option::ClassConstantPrefix, scope->getId().c_str(), Option::IdPrefix.c_str(), var->getName().c_str(), Option::IdPrefix.c_str()); } else if (isString && scalarExp) { cg_printf("LITSTR_INIT(%s)", scalarExp->getCPPLiteralString().c_str()); } else { value->outputCPP(cg, ar); } cg_printf(isString ? ");\n" : ";\n"); value->outputCPPEnd(cg, ar); break; } default: assert(false); } } }
bool ObjectPropertyExpression::outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar, bool noEvalOnError) { if (m_object->isThis()) { TypePtr thisImplType(m_object->getImplementedType()); TypePtr thisActType (m_object->getActualType()); bool close = false; if (m_valid && thisImplType) { ASSERT(thisActType); ASSERT(!Type::SameType(thisActType, thisImplType)); ClassScopePtr implCls(thisImplType->getClass(ar, getScope())); if (implCls && !implCls->derivesFrom(ar, thisActType->getName(), true, false)) { // This happens in this case: // if ($this instanceof Y) { // ... $this->prop ... // } ClassScopePtr cls(thisActType->getClass(ar, getScope())); ASSERT(cls && !cls->derivedByDynamic()); // since we don't do type // assertions for these cg_printf("static_cast<%s%s*>(", Option::ClassPrefix, cls->getId().c_str()); close = true; } } if (m_valid) { if (!m_object->getOriginalClass()) { m_valid = false; } else { FunctionScopeRawPtr fs = m_object->getOriginalFunction(); if (!fs || fs->isStatic()) { m_valid = false; } else if (m_object->getOriginalClass() != getClassScope()) { if (m_object->getOriginalClass()->isRedeclaring()) { m_valid = false; } else { m_objectClass = getClassScope(); } } } } if (m_valid) { if (close) cg_printf("this"); } else { if (!getClassScope() || getClassScope()->derivedByDynamic() || !static_pointer_cast<SimpleVariable>(m_object)->isGuardedThis()) { if (close) { cg_printf("GET_THIS_VALID()"); } else { cg_printf("GET_THIS_ARROW()"); } } } if (close) { cg_printf(")->"); } } else if (m_valid) { TypePtr act; if (!m_object->hasCPPTemp() && m_object->getImplementedType() && !Type::SameType(m_object->getImplementedType(), m_object->getActualType())) { act = m_object->getActualType(); m_object->setActualType(m_object->getImplementedType()); ClassScopePtr cls = ar->findExactClass(shared_from_this(), act->getName()); cg_printf("((%s%s*)", Option::ClassPrefix, cls->getId().c_str()); } m_object->outputCPP(cg, ar); if (act) { if (m_object->getImplementedType()->is(Type::KindOfObject)) { cg_printf(".get())"); } else { cg_printf(".getObjectData())"); } m_object->setActualType(act); } cg_printf("->"); } else { TypePtr t = m_object->getType(); bool ok = t && (t->is(Type::KindOfObject) || t->is(Type::KindOfVariant)); if (noEvalOnError && !ok) { if (!t || !t->is(Type::KindOfArray)) { cg_printf("("); if (m_object->outputCPPUnneeded(cg, ar)) cg_printf(", "); return true; } } ok = ok || !t; if (!ok) cg_printf("Variant("); m_object->outputCPP(cg, ar); if (!ok) cg_printf(")"); cg_printf("."); } if (m_valid && m_propSym->isPrivate() && m_objectClass != getOriginalClass()) { cg_printf("%s%s::", Option::ClassPrefix, getOriginalClass()->getId().c_str()); } return false; }