static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp, bool ref, bool array, bool varnr) { bool close = false; if (ref) { cg_printf("ref("); close = true; } else if (array && !exp->hasCPPTemp() && !exp->isTemporary() && !exp->isScalar() && exp->getActualType() && !exp->getActualType()->isPrimitive() && exp->getActualType()->getKindOf() != Type::KindOfString) { cg_printf("wrap_variant("); close = true; } else if (varnr && exp->getCPPType()->isExactType()) { bool isScalar = exp->isScalar(); if (!isScalar || !Option::UseScalarVariant) { cg_printf("VarNR("); close = true; } else if (isScalar) { ASSERT(!cg.hasScalarVariant()); cg.setScalarVariant(); } } exp->outputCPP(cg, ar); cg.clearScalarVariant(); if (close) cg_printf(")"); }
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultConstPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } if (m_class) { updateClassName(); if (m_class) { return ExpressionPtr(); } } ClassScopePtr cls = resolveClass(); if (!cls || (cls->isVolatile() && !isPresent())) { if (cls && !m_depsSet) { cls->addUse(getScope(), BlockScope::UseKindConstRef); m_depsSet = true; } return ExpressionPtr(); } ConstantTablePtr constants = cls->getConstants(); ClassScopePtr defClass = cls; ConstructPtr decl = constants->getValueRecur(ar, m_varName, defClass); if (decl) { BlockScope::s_constMutex.lock(); ExpressionPtr value = dynamic_pointer_cast<Expression>(decl); BlockScope::s_constMutex.unlock(); if (!value->isScalar() && (value->is(KindOfClassConstantExpression) || value->is(KindOfConstantExpression))) { std::set<ExpressionPtr> seen; do { if (!seen.insert(value).second) return ExpressionPtr(); value = value->preOptimize(ar); if (!value) return ExpressionPtr(); } while (!value->isScalar() && (value->is(KindOfClassConstantExpression) || value->is(KindOfConstantExpression))); } ExpressionPtr rep = Clone(value, getScope()); rep->setComment(getText()); copyLocationTo(rep); return replaceValue(rep); } return ExpressionPtr(); }
bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_variable->is(Expression::KindOfArrayElementExpression)) { ExpressionPtr exp = m_value; ExpressionPtr vv( static_pointer_cast<ArrayElementExpression>(m_variable)->getVariable()); if ((vv->is(KindOfArrayElementExpression) || vv->is(KindOfObjectPropertyExpression)) && (vv->getContainedEffects() && (CreateEffect|AccessorEffect))) { /* We are in a case such as $a->b['c'] = ...; $a['b']['c'] = ...; Where evaluating m_variable may modify $a. Unless we can prove that the rhs is not referring to the same thing as $a, we must generate a temporary for it (note that we could do better with the following checks). */ if (!(m_ref && exp->isRefable()) && !exp->isTemporary() && !exp->isScalar() && exp->getActualType() && !exp->getActualType()->isPrimitive() && exp->getActualType()->getKindOf() != Type::KindOfString) { state |= Expression::StashAll; } } } return Expression::preOutputCPP(cg, ar, state); }
void SwitchStatement::analyzeProgram(AnalysisResultPtr ar) { m_exp->analyzeProgram(ar); if (m_cases) m_cases->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll && m_exp->is(Expression::KindOfSimpleVariable)) { auto exp = dynamic_pointer_cast<SimpleVariable>(m_exp); if (exp && exp->getSymbol() && exp->getSymbol()->isClassName()) { // Mark some classes as volatile since the name is used in switch for (int i = 0; i < m_cases->getCount(); i++) { auto stmt = dynamic_pointer_cast<CaseStatement>((*m_cases)[i]); assert(stmt); ExpressionPtr caseCond = stmt->getCondition(); if (caseCond && caseCond->isScalar()) { auto name = dynamic_pointer_cast<ScalarExpression>(caseCond); if (name && name->isLiteralString()) { string className = name->getLiteralString(); ClassScopePtr cls = ar->findClass(toLower(className)); if (cls && cls->isUserClass()) { cls->setVolatile(); } } } } // Also note this down as code error ConstructPtr self = shared_from_this(); Compiler::Error(Compiler::ConditionalClassLoading, self); } } }
void FunctionCall::optimizeArgArray(AnalysisResultPtr ar) { if (m_extraArg <= 0) return; int paramCount = m_params->getOutputCount(); int iMax = paramCount - m_extraArg; bool isScalar = true; for (int i = iMax; i < paramCount; i++) { ExpressionPtr param = (*m_params)[i]; if (!param->isScalar()) { isScalar = false; break; } } if (isScalar) { ExpressionPtr argArrayPairs = ExpressionListPtr(new ExpressionList(getLocation(), Expression::KindOfExpressionList)); for (int i = iMax; i < paramCount; i++) { ExpressionPtr param = (*m_params)[i]; argArrayPairs->addElement(ArrayPairExpressionPtr( new ArrayPairExpression(param->getLocation(), Expression::KindOfArrayPairExpression, ExpressionPtr(), param, false))); } m_argArrayId = ar->registerScalarArray(argArrayPairs); } }
ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) { if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) { return ExpressionPtr(); } ExpressionPtr val = m_value; while (val) { if (val->is(KindOfExpressionList)) { val = static_pointer_cast<ExpressionList>(val)->listValue(); continue; } if (val->is(KindOfAssignmentExpression)) { val = static_pointer_cast<AssignmentExpression>(val)->m_value; continue; } break; } if (val && val->isScalar()) { if (val != m_value) { ExpressionListPtr rep(new ExpressionList( getScope(), getRange(), ExpressionList::ListKindWrapped)); rep->addElement(m_value); m_value = val->clone(); rep->addElement(static_pointer_cast<Expression>(shared_from_this())); return replaceValue(rep); } } return ExpressionPtr(); }
TypePtr AssignmentExpression:: inferTypesImpl(AnalysisResultPtr ar, TypePtr type, bool coerce, ExpressionPtr variable, ExpressionPtr value /* = ExpressionPtr() */) { TypePtr ret = type; if (value) { if (coerce) { ret = value->inferAndCheck(ar, type, coerce); } else { ret = value->inferAndCheck(ar, NEW_TYPE(Some), coerce); } } BlockScopePtr scope = ar->getScope(); if (variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(variable); bool p; scope->getConstants()->check(exp->getName(), ret, true, ar, variable, p); } else if (variable->is(Expression::KindOfDynamicVariable)) { // simptodo: not too sure about this ar->getFileScope()->setAttribute(FileScope::ContainsLDynamicVariable); } else if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (var->getName() == "this" && ar->getClassScope()) { if (ar->isFirstPass()) { ar->getCodeError()->record(variable, CodeError::ReassignThis, variable); } } if (ar->getPhase() == AnalysisResult::LastInference && value) { if (!value->getExpectedType()) { value->setExpectedType(variable->getActualType()); } } } // if the value may involve object, consider the variable as "referenced" // so that objects are not destructed prematurely. bool referenced = true; if (value && value->isScalar()) referenced = false; if (ret && ret->isNoObjectInvolved()) referenced = false; if (referenced && variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); const std::string &name = var->getName(); VariableTablePtr variables = ar->getScope()->getVariables(); variables->addReferenced(name); } TypePtr vt = variable->inferAndCheck(ar, ret, true); if (!coerce && type->is(Type::KindOfAny)) { ret = vt; } return ret; }
bool Expression::CheckNeededRHS(ExpressionPtr value) { bool needed = true; always_assert(value); while (value->is(KindOfAssignmentExpression)) { value = dynamic_pointer_cast<AssignmentExpression>(value)->getValue(); } if (value->isScalar()) { needed = false; } return needed; }
bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state) { if (m_variable->is(Expression::KindOfArrayElementExpression)) { ExpressionPtr exp = m_value; if (!(m_ref && exp->isRefable()) && !exp->isTemporary() && !exp->isScalar() && exp->getActualType() && !exp->getActualType()->isPrimitive() && exp->getActualType()->getKindOf() != Type::KindOfString) { state |= Expression::StashAll; } } return Expression::preOutputCPP(cg, ar, state); }
ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } ConstructPtr decl; while (!isScalar() && !m_dynamic && !(m_context & LValue)) { const Symbol *sym = resolveNS(ar); if (sym && (!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic())) { sym = 0; m_dynamic = true; } if (!sym) break; if (!sym->isSystem()) BlockScope::s_constMutex.lock(); ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue()); if (!sym->isSystem()) BlockScope::s_constMutex.unlock(); if (!value || !value->isScalar()) { if (!m_depsSet && sym->getDeclaration()) { sym->getDeclaration()->getScope()->addUse( getScope(), BlockScope::UseKindConstRef); m_depsSet = true; } break; } Variant scalarValue; if (value->getScalarValue(scalarValue) && !scalarValue.isAllowedAsConstantValue()) { // block further optimization const_cast<Symbol*>(sym)->setDynamic(); m_dynamic = true; break; } if (sym->isSystem() && !value->is(KindOfScalarExpression)) { if (ExpressionPtr opt = value->preOptimize(ar)) { value = opt; } } ExpressionPtr rep = Clone(value, getScope()); rep->setComment(getText()); copyLocationTo(rep); return replaceValue(rep); } return ExpressionPtr(); }
ExpressionPtr StatementList::getEffectiveImpl(AnalysisResultConstPtr ar) const { for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr s = m_stmts[i]; if (s->is(KindOfReturnStatement)) { ExpressionPtr e = static_pointer_cast<ReturnStatement>(s)->getRetExp(); if (!e) { e = CONSTANT("null"); } else if (!e->isScalar()) { break; } return e; } if (m_stmts[i]->hasImpl()) break; } return ExpressionPtr(); }
static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar, ExpressionPtr exp, bool ref, bool array) { bool close = false; if (ref) { cg_printf("ref("); close = true; } else if (array && !exp->hasCPPTemp() && !exp->isTemporary() && !exp->isScalar() && exp->getActualType() && !exp->getActualType()->isPrimitive() && exp->getActualType()->getKindOf() != Type::KindOfString) { cg_printf("wrap_variant("); close = true; } exp->outputCPP(cg, ar); if (close) cg_printf(")"); }
bool SimpleFunctionCall::isDefineWithoutImpl(AnalysisResultPtr ar) { if (!m_className.empty()) return false; if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) { if (m_dynamicConstant) return false; ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); if (!name) return false; string varName = name->getIdentifier(); if (varName.empty()) return false; if (ar->getConstants()->isSystem(varName)) return true; ExpressionPtr value = (*m_params)[1]; return (!ar->isConstantRedeclared(varName)) && value->isScalar(); } else { return false; } }
void ExpressionList::outputCPPUniqLitKeyArrayInit( CodeGenerator &cg, AnalysisResultPtr ar, bool litstrKeys, int64 num, bool arrayElements /* = true */, unsigned int start /* = 0 */) { if (arrayElements) ASSERT(m_arrayElements); unsigned int n = m_exps.size(); cg_printf("array_createv%c(%lld, ", litstrKeys ? 's' : 'i', num); assert(n - start == num); for (unsigned int i = start; i < n; i++) { ExpressionPtr exp = m_exps[i]; assert(exp); ExpressionPtr name; ExpressionPtr value = exp; if (arrayElements) { ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]); name = ap->getName(); value = ap->getValue(); } if (name) { assert(litstrKeys); cg_printf("toSPOD("); name->outputCPP(cg, ar); cg_printf("), "); } cg_printf("toVPOD("); if (value->isScalar()) { assert(!cg.hasScalarVariant()); cg.setScalarVariant(); if (!Option::UseScalarVariant) cg_printf("VarNR("); value->outputCPP(cg, ar); if (!Option::UseScalarVariant) cg_printf(")"); cg.clearScalarVariant(); } else { bool wrap = Expression::CheckVarNR(value, Type::Variant); if (wrap) cg_printf("VarNR("); value->outputCPP(cg, ar); if (wrap) cg_printf(")"); } cg_printf(")"); if (i < n-1) { cg_printf(", "); } else { cg_printf(")"); } } }
bool Expression::CheckNeededRHS(ExpressionPtr value) { bool needed = true; always_assert(value); while (value->is(KindOfAssignmentExpression)) { value = dynamic_pointer_cast<AssignmentExpression>(value)->getValue(); } if (value->isScalar()) { needed = false; } else { TypePtr type = value->getType(); if (type && (type->is(Type::KindOfSome) || type->is(Type::KindOfAny))) { type = value->getActualType(); } if (type && type->isNoObjectInvolved()) needed = false; } return needed; }
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return ExpressionPtr(); } if (m_redeclared) return ExpressionPtr(); ClassScopePtr cls = ar->resolveClass(m_className); if (!cls || cls->isRedeclaring()) return ExpressionPtr(); ConstantTablePtr constants = cls->getConstants(); if (constants->isExplicitlyDeclared(m_varName)) { ConstructPtr decl = constants->getValue(m_varName); if (decl) { ExpressionPtr value = dynamic_pointer_cast<Expression>(decl); if (!m_visited) { m_visited = true; ar->pushScope(cls); ExpressionPtr optExp = value->preOptimize(ar); ar->popScope(); m_visited = false; if (optExp) value = optExp; } if (value->isScalar()) { // inline the value if (value->is(Expression::KindOfScalarExpression)) { ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(Clone(value)); exp->setComment(getText()); return exp; } else if (value->is(Expression::KindOfConstantExpression)) { // inline the value ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(Clone(value)); exp->setComment(getText()); return exp; } } } } return ExpressionPtr(); }
ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultPtr ar) { ar->preOptimize(m_nameExp); ar->preOptimize(m_params); if (ar->getPhase() != AnalysisResult::SecondPreOptimize) { return ExpressionPtr(); } // optimize away various "exists" functions, this may trigger // dead code elimination and improve type-inference. if (m_className.empty() && (m_type == DefinedFunction || m_type == FunctionExistsFunction || m_type == ClassExistsFunction || m_type == InterfaceExistsFunction) && m_params && m_params->getCount() == 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { string symbol = name->getLiteralString(); switch (m_type) { case DefinedFunction: { ConstantTablePtr constants = ar->getConstants(); // system constant if (constants->isPresent(symbol)) { return CONSTANT("true"); } // user constant BlockScopePtr block = ar->findConstantDeclarer(symbol); // not found (i.e., undefined) if (!block) { if (symbol.find("::") == std::string::npos) { return CONSTANT("false"); } else { // e.g., defined("self::ZERO") return ExpressionPtr(); } } constants = block->getConstants(); // already set to be dynamic if (constants->isDynamic(symbol)) return ExpressionPtr(); ConstructPtr decl = constants->getValue(symbol); ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl); if (constValue->isScalar()) { return CONSTANT("true"); } else { return ExpressionPtr(); } break; } case FunctionExistsFunction: { const std::string &lname = Util::toLower(symbol); if (Option::DynamicInvokeFunctions.find(lname) == Option::DynamicInvokeFunctions.end()) { FunctionScopePtr func = ar->findFunction(lname); if (!func) { return CONSTANT("false"); } else if (!func->isVolatile()) { return CONSTANT("true"); } } break; } case InterfaceExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (!cls || !cls->isInterface()) { return CONSTANT("false"); } else if (!cls->isVolatile()) { return CONSTANT("true"); } break; } case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (!cls || cls->isInterface()) { return CONSTANT("false"); } else if (!cls->isVolatile()) { return CONSTANT("true"); } break; } default: ASSERT(false); } } } } return ExpressionPtr(); }
ExpressionPtr FunctionCall::inliner(AnalysisResultConstPtr ar, ExpressionPtr obj, std::string localThis) { FunctionScopePtr fs = getFunctionScope(); if (m_noInline || !fs || fs == m_funcScope || !m_funcScope->getStmt()) { return ExpressionPtr(); } BlockScope::s_jobStateMutex.lock(); if (m_funcScope->getMark() == BlockScope::MarkProcessing) { fs->setForceRerun(true); BlockScope::s_jobStateMutex.unlock(); return ExpressionPtr(); } ReadLock lock(m_funcScope->getInlineMutex()); BlockScope::s_jobStateMutex.unlock(); if (!m_funcScope->getInlineAsExpr()) { return ExpressionPtr(); } if (m_funcScope->getInlineSameContext() && m_funcScope->getContainingClass() && m_funcScope->getContainingClass() != getClassScope()) { /* The function contains a context sensitive construct such as call_user_func (context sensitive because it could call array('parent', 'foo')) so its not safe to inline it into a different context. */ return ExpressionPtr(); } MethodStatementPtr m (dynamic_pointer_cast<MethodStatement>(m_funcScope->getStmt())); VariableTablePtr vt = fs->getVariables(); int nAct = m_params ? m_params->getCount() : 0; int nMax = m_funcScope->getMaxParamCount(); if (nAct < m_funcScope->getMinParamCount() || !m->getStmts()) { return ExpressionPtr(); } InlineCloneInfo info(m_funcScope); info.elist = ExpressionListPtr(new ExpressionList( getScope(), getLocation(), ExpressionList::ListKindWrapped)); std::ostringstream oss; oss << fs->nextInlineIndex() << "_" << m_name << "_"; std::string prefix = oss.str(); if (obj) { info.callWithThis = true; if (!obj->isThis()) { SimpleVariablePtr var (new SimpleVariable(getScope(), obj->getLocation(), prefix + "this")); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), obj->getLocation(), var, obj, false)); info.elist->addElement(ae); info.sepm[var->getName()] = var; info.localThis = var->getName(); } } else { if (m_classScope) { if (!m_funcScope->isStatic()) { ClassScopeRawPtr oCls = getOriginalClass(); FunctionScopeRawPtr oFunc = getOriginalFunction(); if (oCls && !oFunc->isStatic() && (oCls == m_classScope || oCls->derivesFrom(ar, m_className, true, false))) { info.callWithThis = true; info.localThis = localThis; } } if (!isSelf() && !isParent() && !isStatic()) { info.staticClass = m_className; } } } ExpressionListPtr plist = m->getParams(); int i; for (i = 0; i < nMax || i < nAct; i++) { ParameterExpressionPtr param (i < nMax ? dynamic_pointer_cast<ParameterExpression>((*plist)[i]) : ParameterExpressionPtr()); ExpressionPtr arg = i < nAct ? (*m_params)[i] : Clone(param->defaultValue(), getScope()); SimpleVariablePtr var (new SimpleVariable(getScope(), (i < nAct ? arg.get() : this)->getLocation(), prefix + (param ? param->getName() : lexical_cast<string>(i)))); var->updateSymbol(SimpleVariablePtr()); var->getSymbol()->setHidden(); var->getSymbol()->setUsed(); var->getSymbol()->setReferenced(); bool ref = (i < nMax && m_funcScope->isRefParam(i)) || arg->hasContext(RefParameter); arg->clearContext(RefParameter); AssignmentExpressionPtr ae (new AssignmentExpression(getScope(), arg->getLocation(), var, arg, ref)); info.elist->addElement(ae); if (i < nAct && (ref || !arg->isScalar())) { info.sepm[var->getName()] = var; } } if (cloneStmtsForInline(info, m->getStmts(), prefix, ar, getFunctionScope()) <= 0) { info.elist->addElement(makeConstant(ar, "null")); } if (info.sepm.size()) { ExpressionListPtr unset_list (new ExpressionList(getScope(), getLocation())); for (StringToExpressionPtrMap::iterator it = info.sepm.begin(), end = info.sepm.end(); it != end; ++it) { ExpressionPtr var = it->second->clone(); var->clearContext((Context)(unsigned)-1); unset_list->addElement(var); } ExpressionPtr unset( new UnaryOpExpression(getScope(), getLocation(), unset_list, T_UNSET, true)); i = info.elist->getCount(); ExpressionPtr ret = (*info.elist)[--i]; if (ret->isScalar()) { info.elist->insertElement(unset, i); } else { ExpressionListPtr result_list (new ExpressionList(getScope(), getLocation(), ExpressionList::ListKindLeft)); if (ret->hasContext(LValue)) { result_list->setContext(LValue); result_list->setContext(ReturnContext); } result_list->addElement(ret); result_list->addElement(unset); (*info.elist)[i] = result_list; } } recomputeEffects(); return replaceValue(info.elist); }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if (num <= MAX_CONCAT_ARGS) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': if (!first->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = first->hasCPPTemp() ? first->getType() : first->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_SL: case T_SR: ASSERT(first->getType()->is(Type::KindOfInt64)); first->outputCPP(cg, ar); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': if (!second->outputCPPArithArg(cg, ar, m_op == '+')) { TypePtr argType = second->hasCPPTemp() ? second->getType() : second->getActualType(); bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; case T_INSTANCEOF: { if (second->isScalar()) { ScalarExpressionPtr scalar = dynamic_pointer_cast<ScalarExpression>(second); bool notQuoted = scalar && !scalar->isQuoted(); std::string s = second->getLiteralString(); if (s == "static" && notQuoted) { cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())"); } else if (s != "") { if (s == "self" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls) { s = cls->getOriginalName(); } } else if (s == "parent" && notQuoted) { ClassScopeRawPtr cls = getOriginalClass(); if (cls && !cls->getParent().empty()) { s = cls->getParent(); } } cg_printString(s, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
StatementPtr IfStatement::preOptimize(AnalysisResultPtr ar) { if (ar->getPhase() < AnalysisResult::FirstPreOptimize) { return StatementPtr(); } // we cannot optimize away the code inside if statement, because // there may be a goto that goes into if statement. if (hasReachableLabel()) { return StatementPtr(); } bool changed = false; int i; int j; Variant value; bool hoist = false; for (i = 0; i < m_stmts->getCount(); i++) { IfBranchStatementPtr branch = dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[i]); ExpressionPtr condition = branch->getCondition(); if (!condition) { StatementPtr stmt = branch->getStmt(); if (stmt) { if (!i && ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) || !stmt->hasDecl())) { hoist = true; break; } if (stmt->is(KindOfIfStatement)) { StatementListPtr sub_stmts = dynamic_pointer_cast<IfStatement>(stmt)->m_stmts; m_stmts->removeElement(i); changed = true; for (j = 0; j < sub_stmts->getCount(); j++) { m_stmts->insertElement((*sub_stmts)[j], i++); } } } break; } else if (condition->isScalar() && condition->getScalarValue(value)) { if (value.toBoolean()) { hoist = !i && ((getFunctionScope() && !getFunctionScope()->inPseudoMain()) || !branch->hasDecl()); break; } else { m_stmts->removeElement(i--); changed = true; } } } if (!changed && i && i == m_stmts->getCount()) return StatementPtr(); // either else branch or if (true) branch without further declarations i++; while (i < m_stmts->getCount()) { m_stmts->removeElement(i); changed = true; } // if there is only one branch left, return stmt. if (hoist) { IfBranchStatementPtr branch = dynamic_pointer_cast<IfBranchStatement>((*m_stmts)[0]); return branch->getStmt() ? branch->getStmt() : NULL_STATEMENT(); } else if (m_stmts->getCount() == 0) { return NULL_STATEMENT(); } else { return changed ? static_pointer_cast<Statement>(shared_from_this()) : StatementPtr(); } }
ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) { if (Option::EliminateDeadCode && ar->getPhase() >= AnalysisResult::FirstPreOptimize) { // otherwise used & needed flags may not be up to date yet ExpressionPtr rep = optimize(ar); if (rep) return rep; } if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) { return ExpressionPtr(); } ExpressionPtr val = m_value; while (val) { if (val->is(KindOfExpressionList)) { ExpressionListPtr el(static_pointer_cast<ExpressionList>(val)); val = el->listValue(); continue; } if (val->is(KindOfAssignmentExpression)) { val = static_pointer_cast<AssignmentExpression>(val)->m_value; continue; } break; } if (val && val->isScalar()) { if (val != m_value) { ExpressionListPtr rep(new ExpressionList( getScope(), getLocation(), KindOfExpressionList, ExpressionList::ListKindWrapped)); rep->addElement(m_value); m_value = val->clone(); rep->addElement(static_pointer_cast<Expression>(shared_from_this())); return replaceValue(rep); } if (!m_ref && m_variable->is(KindOfArrayElementExpression)) { ArrayElementExpressionPtr ae( static_pointer_cast<ArrayElementExpression>(m_variable)); ExpressionPtr avar(ae->getVariable()); ExpressionPtr aoff(ae->getOffset()); if (!aoff || aoff->isScalar()) { avar = avar->getCanonLVal(); while (avar) { if (avar->isScalar()) { Variant v,o,r; if (!avar->getScalarValue(v)) break; if (!val->getScalarValue(r)) break; try { g_context->setThrowAllErrors(true); if (aoff) { if (!aoff->getScalarValue(o)) break; v.set(o, r); } else { v.append(r); } g_context->setThrowAllErrors(false); } catch (...) { break; } ExpressionPtr rep( new AssignmentExpression( getScope(), getLocation(), KindOfAssignmentExpression, m_variable->replaceValue(Clone(ae->getVariable())), makeScalarExpression(ar, v), false)); if (!isUnused()) { ExpressionListPtr el( new ExpressionList( getScope(), getLocation(), KindOfExpressionList, ExpressionList::ListKindWrapped)); el->addElement(rep); el->addElement(val); rep = el; } return replaceValue(rep); } avar = avar->getCanonPtr(); } g_context->setThrowAllErrors(false); } } } return ExpressionPtr(); }
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return; bool wrapped = true; switch (m_op) { case T_CONCAT_EQUAL: if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) { SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1); ExpressionPtrVec ev; bool hasVoid = false; getConcatList(ev, m_exp2, hasVoid); cg_printf("%s", stringBufferName(Option::TempPrefix, prefix, sv->getName().c_str()).c_str()); outputStringBufExprs(ev, cg, ar); return; } cg_printf("concat_assign"); break; case '.': { ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this()); ExpressionPtrVec ev; bool hasVoid = false; int num = getConcatList(ev, self, hasVoid); assert(!hasVoid); if ((num <= MAX_CONCAT_ARGS || (Option::GenConcat && cg.getOutput() != CodeGenerator::SystemCPP))) { assert(num >= 2); if (num == 2) { cg_printf("concat("); } else { if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num); cg_printf("concat%d(", num); } for (size_t i = 0; i < ev.size(); i++) { ExpressionPtr exp = ev[i]; if (i) cg_printf(", "); outputStringExpr(cg, ar, exp, false); } cg_printf(")"); } else { cg_printf("StringBuffer()"); outputStringBufExprs(ev, cg, ar); cg_printf(".detach()"); } } return; case T_LOGICAL_XOR: cg_printf("logical_xor"); break; case '|': cg_printf("bitwise_or"); break; case '&': cg_printf("bitwise_and"); break; case '^': cg_printf("bitwise_xor"); break; case T_IS_IDENTICAL: cg_printf("same"); break; case T_IS_NOT_IDENTICAL: cg_printf("!same"); break; case T_IS_EQUAL: cg_printf("equal"); break; case T_IS_NOT_EQUAL: cg_printf("!equal"); break; case '<': cg_printf("less"); break; case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break; case '>': cg_printf("more"); break; case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break; case '/': cg_printf("divide"); break; case '%': cg_printf("modulo"); break; case T_INSTANCEOF: cg_printf("instanceOf"); break; default: wrapped = !isUnused(); break; } if (wrapped) cg_printf("("); ExpressionPtr first = m_exp1; ExpressionPtr second = m_exp2; // we could implement these functions natively on String and Array classes switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = first->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); first->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); first->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_SL: case T_SR: cg_printf("toInt64("); first->outputCPP(cg, ar); cg_printf(")"); break; default: first->outputCPP(cg, ar); break; } switch (m_op) { case T_PLUS_EQUAL: cg_printf(" += "); break; case T_MINUS_EQUAL: cg_printf(" -= "); break; case T_MUL_EQUAL: cg_printf(" *= "); break; case T_DIV_EQUAL: cg_printf(" /= "); break; case T_MOD_EQUAL: cg_printf(" %%= "); break; case T_AND_EQUAL: cg_printf(" &= "); break; case T_OR_EQUAL: cg_printf(" |= "); break; case T_XOR_EQUAL: cg_printf(" ^= "); break; case T_SL_EQUAL: cg_printf(" <<= "); break; case T_SR_EQUAL: cg_printf(" >>= "); break; case T_BOOLEAN_OR: cg_printf(" || "); break; case T_BOOLEAN_AND: cg_printf(" && "); break; case T_LOGICAL_OR: cg_printf(" || "); break; case T_LOGICAL_AND: cg_printf(" && "); break; default: switch (m_op) { case '+': cg_printf(" + "); break; case '-': cg_printf(" - "); break; case '*': cg_printf(" * "); break; case T_SL: cg_printf(" << "); break; case T_SR: cg_printf(" >> "); break; default: cg_printf(", "); break; } break; } switch (m_op) { case '+': case '-': case '*': case '/': { TypePtr actualType = second->getActualType(); if (actualType && (actualType->is(Type::KindOfString) || (m_op != '+' && actualType->is(Type::KindOfArray)))) { cg_printf("(Variant)("); second->outputCPP(cg, ar); cg_printf(")"); } else { bool flag = castIfNeeded(getActualType(), actualType, cg, ar, getScope()); second->outputCPP(cg, ar); if (flag) { cg_printf(")"); } } break; } case T_INSTANCEOF: { if (second->isScalar()) { std::string s = second->getLiteralString(); std::string sLower = Util::toLower(s); if (sLower != "") { cg_printString(sLower, ar, shared_from_this()); } else { second->outputCPP(cg, ar); } } else { second->outputCPP(cg, ar); } break; } case T_PLUS_EQUAL: case T_MINUS_EQUAL: case T_MUL_EQUAL: { TypePtr t1 = first->getCPPType(); TypePtr t2 = second->getType(); if (t1 && !t1->is(Type::KindOfArray) && t2 && Type::IsCastNeeded(ar, t2, t1)) { t1->outputCPPCast(cg, ar, getScope()); cg_printf("("); second->outputCPP(cg, ar); cg_printf(")"); } else { second->outputCPP(cg, ar); } break; } case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_AND: case T_LOGICAL_OR: if (isUnused()) { cg_printf("("); if (second->outputCPPUnneeded(cg, ar)) { cg_printf(","); } cg_printf("false)"); } else { second->outputCPP(cg, ar); } break; default: second->outputCPP(cg, ar); } if (wrapped) cg_printf(")"); }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic() && !isStaticMethodAutoFixed()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (!m_docComment.empty()) attribute |= ClassInfo::HasDocComment; // Use the original cased name, for reflection to work correctly. cg.printf("(const char *)0x%04X, \"%s\", NULL, NULL,\n", attribute, getOriginalName().c_str()); if (!m_docComment.empty()) { char *dc = string_cplus_escape(m_docComment.c_str()); cg.printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; cg.printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(m_paramTypes[i]->getPHPName()).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); if (!def->isScalar() || !def->getScalarValue(defArg)) { defArg = "1"; } } else { defArg = "1"; } char *s = string_cplus_escape(f_serialize(defArg).data()); cg.printf("\"%s\",\n", s); free(s); } else { cg.printf("\"\",\n"); } } cg.printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { bool linemap = outputLineMap(cg, ar, true); if (!m_lambda.empty()) { cg.printf("\"%s\"", m_lambda.c_str()); if (linemap) cg.printf(")"); return; } if (m_className.empty()) { if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); ExpressionPtr value = (*m_params)[1]; if (varName.empty()) { cg.printf("throw_fatal(\"bad define\")"); } else if (m_dynamicConstant) { cg.printf("g->declareConstant(\"%s\", g->%s%s, ", varName.c_str(), Option::ConstantPrefix, varName.c_str()); value->outputCPP(cg, ar); cg.printf(")"); } else { bool needAssignment = true; bool isSystem = ar->getConstants()->isSystem(varName); if (isSystem || ((!ar->isConstantRedeclared(varName)) && value->isScalar())) { needAssignment = false; } if (needAssignment) { cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str()); value->outputCPP(cg, ar); } } } else { cg.printf("throw_fatal(\"bad define\")"); } if (linemap) cg.printf(")"); return; } if (m_name == "func_num_args") { cg.printf("num_args"); if (linemap) cg.printf(")"); return; } switch (m_type) { case VariableArgumentFunction: { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(ar->getScope()); if (func) { cg.printf("%s(", m_name.c_str()); func->outputCPPParamsCall(cg, ar, true); if (m_params) { cg.printf(","); m_params->outputCPP(cg, ar); } cg.printf(")"); if (linemap) cg.printf(")"); return; } } break; case FunctionExistsFunction: case ClassExistsFunction: case InterfaceExistsFunction: { bool literalString = false; string symbol; if (m_params && m_params->getCount() == 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { literalString = true; symbol = name->getLiteralString(); } } } if (literalString) { switch (m_type) { case FunctionExistsFunction: { const std::string &lname = Util::toLower(symbol); bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) != Option::DynamicInvokeFunctions.end(); if (!dynInvoke) { FunctionScopePtr func = ar->findFunction(lname); if (func) { if (!func->isDynamic()) { if (func->isRedeclaring()) { const char *name = func->getName().c_str(); cg.printf("(%s->%s%s != invoke_failed_%s)", cg.getGlobals(ar), Option::InvokePrefix, name, name); break; } cg.printf("true"); break; } } else { cg.printf("false"); break; } } cg.printf("f_function_exists(\"%s\")", lname.c_str()); } break; case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && !cls->isInterface()) { const char *name = cls->getName().c_str(); cg.printf("f_class_exists(\"%s\")", name); } else { cg.printf("false"); } } break; case InterfaceExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && cls->isInterface()) { const char *name = cls->getName().c_str(); cg.printf("f_interface_exists(\"%s\")", name); } else { cg.printf("false"); } } break; default: break; } if (linemap) cg.printf(")"); return; } } break; case GetDefinedVarsFunction: cg.printf("get_defined_vars(variables)"); if (linemap) cg.printf(")"); return; default: break; } } outputCPPParamOrderControlled(cg, ar); if (linemap) cg.printf(")"); }
TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { reset(); ConstructPtr self = shared_from_this(); // handling define("CONSTANT", ...); if (m_className.empty()) { if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); if (!varName.empty()) { ExpressionPtr value = (*m_params)[1]; TypePtr varType = value->inferAndCheck(ar, NEW_TYPE(Some), false); ar->getDependencyGraph()-> addParent(DependencyGraph::KindOfConstant, ar->getName(), varName, self); ConstantTablePtr constants = ar->findConstantDeclarer(varName)->getConstants(); if (constants != ar->getConstants()) { if (value && !value->isScalar()) { constants->setDynamic(ar, varName); varType = Type::Variant; } if (constants->isDynamic(varName)) { m_dynamicConstant = true; ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } else { constants->setType(ar, varName, varType, true); } // in case the old 'value' has been optimized constants->setValue(ar, varName, value); } return checkTypesImpl(ar, type, Type::Boolean, coerce); } } if (varName.empty() && ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::BadDefine, self); } } else if (m_type == ExtractFunction) { ar->getScope()->getVariables()->forceVariants(ar); } } FunctionScopePtr func; // avoid raising both MissingObjectContext and UnknownFunction bool errorFlagged = false; if (m_className.empty()) { func = ar->findFunction(m_name); } else { ClassScopePtr cls = ar->resolveClass(m_className); if (cls && cls->isVolatile()) { ar->getScope()->getVariables() ->setAttribute(VariableTable::NeedGlobalPointer); } if (!cls || cls->isRedeclaring()) { if (cls) { m_redeclaredClass = true; } if (!cls && ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UnknownClass, self); } if (m_params) { m_params->inferAndCheck(ar, NEW_TYPE(Some), false); } return checkTypesImpl(ar, type, Type::Variant, coerce); } m_derivedFromRedeclaring = cls->derivesFromRedeclaring(); m_validClass = true; if (m_name == "__construct") { // if the class is known, php will try to identify class-name ctor func = cls->findConstructor(ar, true); } else { func = cls->findFunction(ar, m_name, true, true); } if (func && !func->isStatic()) { ClassScopePtr clsThis = ar->getClassScope(); FunctionScopePtr funcThis = ar->getFunctionScope(); if (!clsThis || (clsThis->getName() != m_className && !clsThis->derivesFrom(ar, m_className)) || funcThis->isStatic()) { // set the method static to avoid "unknown method" runtime exception if (Option::StaticMethodAutoFix && !func->containsThis()) { func->setStatic(); } if (ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::MissingObjectContext, self); errorFlagged = true; } func.reset(); } } } if (!func || func->isRedeclaring()) { if (func) { m_redeclared = true; ar->getScope()->getVariables()-> setAttribute(VariableTable::NeedGlobalPointer); } if (!func && !errorFlagged && ar->isFirstPass()) { ar->getCodeError()->record(self, CodeError::UnknownFunction, self); } if (m_params) { if (func) { FunctionScope::RefParamInfoPtr info = FunctionScope::GetRefParamInfo(m_name); ASSERT(info); for (int i = m_params->getCount(); i--; ) { if (info->isRefParam(i)) { m_params->markParam(i, canInvokeFewArgs()); } } } m_params->inferAndCheck(ar, NEW_TYPE(Some), false); } return checkTypesImpl(ar, type, Type::Variant, coerce); } m_builtinFunction = !func->isUserFunction(); if (m_redeclared) { if (m_params) { m_params->inferAndCheck(ar, NEW_TYPE(Some), false); } return checkTypesImpl(ar, type, type, coerce); } CHECK_HOOK(beforeSimpleFunctionCallCheck); m_valid = true; type = checkParamsAndReturn(ar, type, coerce, func); if (!m_valid && m_params) { m_params->markParams(false); } CHECK_HOOK(afterSimpleFunctionCallCheck); return type; }
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) { int attribute = ClassInfo::IsNothing; if (!isUserFunction()) attribute |= ClassInfo::IsSystem; if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared; if (isVolatile()) attribute |= ClassInfo::IsVolatile; if (isRefReturn()) attribute |= ClassInfo::IsReference; if (isProtected()) { attribute |= ClassInfo::IsProtected; } else if (isPrivate()) { attribute |= ClassInfo::IsPrivate; } else { attribute |= ClassInfo::IsPublic; } if (isAbstract()) attribute |= ClassInfo::IsAbstract; if (isStatic()) { attribute |= ClassInfo::IsStatic; } if (isFinal()) attribute |= ClassInfo::IsFinal; if (isVariableArgument()) { attribute |= ClassInfo::VariableArguments; } if (isReferenceVariableArgument()) { attribute |= ClassInfo::RefVariableArguments; } if (isMixedVariableArgument()) { attribute |= ClassInfo::MixedVariableArguments; } attribute |= m_attributeClassInfo; if (!m_docComment.empty() && Option::GenerateDocComments) { attribute |= ClassInfo::HasDocComment; } else { attribute &= ~ClassInfo::HasDocComment; } // Use the original cased name, for reflection to work correctly. cg_printf("(const char *)0x%04X, \"%s\", \"%s\", (const char *)%d, " "(const char *)%d, NULL, NULL,\n", attribute, getOriginalName().c_str(), m_stmt ? m_stmt->getLocation()->file : "", m_stmt ? m_stmt->getLocation()->line0 : 0, m_stmt ? m_stmt->getLocation()->line1 : 0); if (!m_docComment.empty() && Option::GenerateDocComments) { char *dc = string_cplus_escape(m_docComment.c_str(), m_docComment.size()); cg_printf("\"%s\",\n", dc); free(dc); } Variant defArg; for (int i = 0; i < m_maxParam; i++) { int attr = ClassInfo::IsNothing; if (i >= m_minParam) attr |= ClassInfo::IsOptional; if (isRefParam(i)) attr |= ClassInfo::IsReference; const std::string &tname = m_paramTypeSpecs[i] ? m_paramTypeSpecs[i]->getPHPName() : ""; cg_printf("(const char *)0x%04X, \"%s\", \"%s\", ", attr, m_paramNames[i].c_str(), Util::toLower(tname).c_str()); if (i >= m_minParam) { MethodStatementPtr m = dynamic_pointer_cast<MethodStatement>(getStmt()); if (m) { ExpressionListPtr params = m->getParams(); assert(i < params->getCount()); ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*params)[i]); assert(param); ExpressionPtr def = param->defaultValue(); string sdef = def->getText(); char *esdef = string_cplus_escape(sdef.data(), sdef.size()); if (!def->isScalar() || !def->getScalarValue(defArg)) { /** * Special value runtime/ext/ext_reflection.cpp can check and throw. * If we want to avoid seeing this so to make getDefaultValue() * work better for reflections, we will have to implement * getScalarValue() to greater extent under compiler/expressions. */ cg_printf("\"\x01\", \"%s\",\n", esdef); } else { String str = f_serialize(defArg); char *s = string_cplus_escape(str.data(), str.size()); cg_printf("\"%s\", \"%s\",\n", s, esdef); free(s); } free(esdef); } else { char *def = string_cplus_escape(m_paramDefaults[i].data(), m_paramDefaults[i].size()); char *defText = string_cplus_escape(m_paramDefaultTexts[i].data(), m_paramDefaultTexts[i].size()); cg_printf("\"%s\", \"%s\",\n", def, defText); free(def); free(defText); } } else { cg_printf("\"\", \"\",\n"); } } cg_printf("NULL,\n"); m_variables->outputCPPStaticVariables(cg, ar); }
void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) { if (m_className.empty()) { addUserFunction(ar, m_name); } else if (m_className != "parent") { addUserClass(ar, m_className); } else { m_parentClass = true; } if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { CHECK_HOOK(onSimpleFunctionCallAnalyzeInclude); ConstructPtr self = shared_from_this(); // We need to know the name of the constant so that we can associate it // with this file before we do type inference. if (m_className.empty() && m_type == DefineFunction) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); if (!varName.empty()) { ar->getFileScope()->declareConstant(ar, varName); } } // handling define("CONSTANT", ...); if (m_params && m_params->getCount() >= 2) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>((*m_params)[0]); string varName; if (name) { varName = name->getIdentifier(); if (!varName.empty()) { ExpressionPtr value = (*m_params)[1]; ConstantTablePtr constants = ar->findConstantDeclarer(varName)->getConstants(); if (constants != ar->getConstants()) { constants->add(varName, NEW_TYPE(Some), value, ar, self); if (name->hasHphpNote("Dynamic")) { constants->setDynamic(ar, varName); } } } } } } if (m_type == UnserializeFunction) { ar->forceClassVariants(); } } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { // Look up the corresponding FunctionScope and ClassScope // for this function call { FunctionScopePtr func; ClassScopePtr cls; if (m_className.empty()) { func = ar->findFunction(m_name); } else { cls = ar->resolveClass(m_className); if (cls) { if (m_name == "__construct") { func = cls->findConstructor(ar, true); } else { func = cls->findFunction(ar, m_name, true, true); } } } if (func && !func->isRedeclaring()) { if (m_funcScope != func) { m_funcScope = func; Construct::recomputeEffects(); } } if (cls && !cls->isRedeclaring()) m_classScope = cls; } // check for dynamic constant and volatile function/class if (m_className.empty() && (m_type == DefinedFunction || m_type == FunctionExistsFunction || m_type == ClassExistsFunction || m_type == InterfaceExistsFunction) && m_params && m_params->getCount() >= 1) { ExpressionPtr value = (*m_params)[0]; if (value->isScalar()) { ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value); if (name && name->isLiteralString()) { string symbol = name->getLiteralString(); switch (m_type) { case DefinedFunction: { ConstantTablePtr constants = ar->getConstants(); if (!constants->isPresent(symbol)) { // user constant BlockScopePtr block = ar->findConstantDeclarer(symbol); if (block) { // found the constant constants = block->getConstants(); // set to be dynamic constants->setDynamic(ar, symbol); } } break; } case FunctionExistsFunction: { FunctionScopePtr func = ar->findFunction(Util::toLower(symbol)); if (func && func->isUserFunction()) { func->setVolatile(); } break; } case InterfaceExistsFunction: case ClassExistsFunction: { ClassScopePtr cls = ar->findClass(Util::toLower(symbol)); if (cls && cls->isUserClass()) { cls->setVolatile(); } break; } default: ASSERT(false); } } } } } if (m_params) { if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (m_funcScope) { ExpressionList ¶ms = *m_params; int mpc = m_funcScope->getMaxParamCount(); for (int i = params.getCount(); i--; ) { ExpressionPtr p = params[i]; if (i < mpc ? m_funcScope->isRefParam(i) : m_funcScope->isReferenceVariableArgument()) { p->setContext(Expression::RefValue); } else if (!(p->getContext() & Expression::RefParameter)) { p->clearContext(Expression::RefValue); } } } else { FunctionScopePtr func = ar->findFunction(m_name); if (func && func->isRedeclaring()) { FunctionScope::RefParamInfoPtr info = FunctionScope::GetRefParamInfo(m_name); if (info) { for (int i = m_params->getCount(); i--; ) { if (info->isRefParam(i)) { m_params->markParam(i, canInvokeFewArgs()); } } } } else { m_params->markParams(false); } } } m_params->analyzeProgram(ar); } }