void StaticStatement::analyzeProgramImpl(AnalysisResultPtr ar) { m_exp->analyzeProgram(ar); BlockScopePtr scope = ar->getScope(); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; ExpressionPtr variable; ExpressionPtr value; if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { // turn static $a; into static $a = null; if (exp->is(Expression::KindOfSimpleVariable)) { variable = dynamic_pointer_cast<SimpleVariable>(exp); exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getLocation(), Expression::KindOfAssignmentExpression, variable, CONSTANT("null"), false)); (*m_exp)[i] = exp; } } if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); variable = assignment_exp->getVariable(); value = assignment_exp->getValue(); } else { ASSERT(false); } SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { if (scope->getVariables()->setStaticInitVal(var->getName(), value)) { ar->getCodeError()->record(CodeError::DeclaredStaticVariableTwice, exp); } } else if (ar->getPhase() == AnalysisResult::AnalyzeAll) { // update initial value const string &name = var->getName(); ExpressionPtr initValue = (dynamic_pointer_cast<Expression> (scope->getVariables()->getStaticInitVal(name)))->clone(); exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getLocation(), Expression::KindOfAssignmentExpression, variable, initValue, false)); (*m_exp)[i] = exp; } } }
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); } }
void StaticStatement::analyzeProgram(AnalysisResultPtr ar) { m_exp->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { BlockScopePtr scope = getScope(); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; ExpressionPtr variable; ExpressionPtr value; // turn static $a; into static $a = null; if (exp->is(Expression::KindOfSimpleVariable)) { variable = dynamic_pointer_cast<SimpleVariable>(exp); exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getScope(), exp->getLocation(), variable, CONSTANT("null"), false)); (*m_exp)[i] = exp; } always_assert(exp->is(Expression::KindOfAssignmentExpression)); AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); variable = assignment_exp->getVariable(); value = assignment_exp->getValue(); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); // set the Declaration context here instead of all over this file - this phase // is the first to run var->setContext(Expression::Declaration); Symbol *sym = var->getSymbol(); sym->setStaticInitVal(value); } } }
void CodeGenerator::printTypeExpression(ExpressionPtr expression) { printObjectHeader("TypeExpression", 2); printPropertyHeader("name"); expression->outputCodeModel(*this); printPropertyHeader("sourceLocation"); printLocation(expression->getLocation()); printObjectFooter(); }
bool Option::GetArrayElements(ExpressionPtr value, ExpressionListPtr &out) { UnaryOpExpressionPtr v = dynamic_pointer_cast<UnaryOpExpression>(value); if (!v || v->getOp() != T_ARRAY) { Logger::Error("Line %d: invalid array: %s", value->getLocation()->line1, value->getText().c_str()); return false; } ExpressionPtr exp = v->getExpression(); out = dynamic_pointer_cast<ExpressionList>(exp); if (!out) { Logger::Error("Line %d: invalid array: %s", value->getLocation()->line1, value->getText().c_str()); return false; } return true; }
bool Option::Load(string &option, ExpressionPtr value) { ScalarExpressionPtr v = dynamic_pointer_cast<ScalarExpression>(value); if (!v || !v->isLiteralString()) { Logger::Error("Line %d: invalid string: %s", value->getLocation()->line1, value->getText().c_str()); return false; } option = v->getLiteralString(); return true; }
bool Option::Load(bool &option, ExpressionPtr value) { ConstantExpressionPtr v = dynamic_pointer_cast<ConstantExpression>(value); if (!v || !v->isBoolean()) { Logger::Error("Line %d: invalid boolean: %s", value->getLocation()->line1, value->getText().c_str()); return false; } option = v->getBooleanValue(); return true; }
void CodeGenerator::printExpression(ExpressionPtr expression, bool isRef) { if (isRef) { printObjectHeader("UnaryOpExpression", 4); printPropertyHeader("expression"); expression->outputCodeModel(*this); printPropertyHeader("operation"); printValue(PHP_REFERENCE_OP); printPropertyHeader("sourceLocation"); printLocation(expression->getLocation()); printObjectFooter(); } else { expression->outputCodeModel(*this); } }
bool Option::Load(map<string, int> &option, ExpressionPtr value) { ExpressionListPtr elements; if (!GetArrayElements(value, elements)) return false; for (int i = 0; i < elements->getCount(); i++) { ExpressionPtr e = (*elements)[i]; ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e); bool negative = false; ScalarExpressionPtr n, v; if (pair) n = dynamic_pointer_cast<ScalarExpression>(pair->getName()); if (pair) { if (pair->getValue()->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr una = dynamic_pointer_cast<UnaryOpExpression>(pair->getValue()); if (una->getOp() != '+' && una->getOp() != '-') { Logger::Error("Line %d: invalid integer: %s", una->getLocation()->line1, una->getText().c_str()); return false; } v = dynamic_pointer_cast<ScalarExpression>(una->getExpression()); if (una->getOp() == '-') { negative = true; } } else { v = dynamic_pointer_cast<ScalarExpression>(pair->getValue()); } } if (!pair || !n || !v || !n->isLiteralString() || !v->isLiteralInteger()) { Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1, e->getText().c_str()); return false; } if (negative) { option[n->getLiteralString()] = - v->getLiteralInteger(); } else { option[n->getLiteralString()] = v->getLiteralInteger(); } } return true; }
bool Option::Load(vector<string> &option, ExpressionPtr value) { ExpressionListPtr elements; if (!GetArrayElements(value, elements)) return false; for (int i = 0; i < elements->getCount(); i++) { ExpressionPtr e = (*elements)[i]; ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e); ScalarExpressionPtr v; if (pair) v = dynamic_pointer_cast<ScalarExpression>(pair->getValue()); if (!pair || !v || !v->isLiteralString()) { Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1, e->getText().c_str()); return false; } option.push_back(v->getLiteralString()); } return true; }
bool StatementList::mergeConcatAssign() { if (Option::LocalCopyProp) { return false; } else { // check for vector string concat assignment such as // $space = " "; // $a .= "hello"; // $a .= $space; // $a .= "world!"; // turn into (for constant folding and concat sequence) // $a .= " " . "hello " . $space . "world!"; unsigned int i = 0; bool merged = false; do { std::string lhsName; int length = 0; for (; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; if (!stmt->is(Statement::KindOfExpStatement)) break; ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt); ExpressionPtr exp = expStmt->getExpression(); // check the first assignment if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr variable = assignment_exp->getVariable(); ExpressionPtr value = assignment_exp->getValue(); std::string variableName = variable->getText(); if (variableName.find("->") != std::string::npos) break; if (value->hasEffect()) break; // cannot turn $a .= $b; a .= $a into $a .= $b . $a; if (value->getText().find(variableName) != std::string::npos) break; if (lhsName.empty()) { lhsName = variable->getText(); length++; continue; } else { break; } } else if (!exp->is(Expression::KindOfBinaryOpExpression)) { break; } BinaryOpExpressionPtr binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp); if (binaryOpExp->getOp() != T_CONCAT_EQUAL) break; ExpressionPtr exp1 = binaryOpExp->getExp1(); std::string exp1Text = exp1->getText(); if (exp1Text.find("->") != std::string::npos) break; ExpressionPtr exp2 = binaryOpExp->getExp2(); if (exp2->hasEffect()) break; if (exp2->getText().find(exp1Text) != std::string::npos) break; if (lhsName.empty()) { lhsName = exp1Text; length++; } else if (lhsName == exp1Text) { length++; } else { break; } } if (length > 1) { // replace m_stmts[j] to m_stmts[i - 1] with a new statement unsigned j = i - length; ExpStatementPtr expStmt; ExpressionPtr exp; BinaryOpExpressionPtr binaryOpExp; ExpressionPtr var; ExpressionPtr exp1; ExpressionPtr exp2; bool isAssignment = false; expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j++]); exp = expStmt->getExpression(); if (exp->is(Expression::KindOfAssignmentExpression)) { isAssignment = true; AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); var = assignment_exp->getVariable(); exp1 = assignment_exp->getValue(); } else { binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp); var = binaryOpExp->getExp1(); exp1 = binaryOpExp->getExp2(); } for (; j < i; j++) { expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j]); exp = expStmt->getExpression(); binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp); exp2 = binaryOpExp->getExp2(); exp1 = BinaryOpExpressionPtr (new BinaryOpExpression(getScope(), getLocation(), Expression::KindOfBinaryOpExpression, exp1, exp2, '.')); } if (isAssignment) { exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getScope(), exp->getLocation(), Expression::KindOfAssignmentExpression, var, exp1, false)); } else { exp = BinaryOpExpressionPtr (new BinaryOpExpression(getScope(), getLocation(), Expression::KindOfBinaryOpExpression, var, exp1, T_CONCAT_EQUAL)); } expStmt = ExpStatementPtr (new ExpStatement(getScope(), getLocation(), Statement::KindOfExpStatement, exp)); m_stmts[i - length] = expStmt; for (j = i - (length - 1); i > j; i--) removeElement(j); merged = true; } else if (length == 0) { i++; } } while (i < m_stmts.size()); return merged; } }
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); }
static ExpressionPtr cloneForInlineRecur(InlineCloneInfo &info, ExpressionPtr exp, const std::string &prefix, AnalysisResultConstPtr ar, FunctionScopePtr scope) { exp->getOriginalScope(); // make sure to cache the original scope exp->setBlockScope(scope); for (int i = 0, n = exp->getKidCount(); i < n; i++) { if (ExpressionPtr k = exp->getNthExpr(i)) { exp->setNthKid(i, cloneForInlineRecur(info, k, prefix, ar, scope)); } } StaticClassName *scn = dynamic_cast<StaticClassName*>(exp.get()); if (scn && scn->isStatic() && !info.staticClass.empty()) { scn->resolveStatic(info.staticClass); } switch (exp->getKindOf()) { case Expression::KindOfSimpleVariable: { SimpleVariablePtr sv(dynamic_pointer_cast<SimpleVariable>(exp)); if (sv->isSuperGlobal()) break; string name; if (sv->isThis()) { if (!info.callWithThis) { if (!sv->hasContext(Expression::ObjectContext)) { exp = sv->makeConstant(ar, "null"); } else { // This will produce the wrong error // we really want a "throw_fatal" ast node. exp = sv->makeConstant(ar, "null"); } break; } if (info.localThis.empty()) break; name = info.localThis; } else { name = prefix + sv->getName(); } SimpleVariablePtr rep(new SimpleVariable( exp->getScope(), exp->getLocation(), name)); rep->copyContext(sv); rep->updateSymbol(SimpleVariablePtr()); rep->getSymbol()->setHidden(); // Conservatively set flags to prevent // the alias manager from getting confused. // On the next pass, it will correct the values, // and optimize appropriately. rep->getSymbol()->setUsed(); rep->getSymbol()->setReferenced(); if (exp->getContext() & (Expression::LValue| Expression::RefValue| Expression::RefParameter)) { info.sepm[name] = rep; } exp = rep; } break; case Expression::KindOfObjectMethodExpression: { FunctionCallPtr call( static_pointer_cast<FunctionCall>(exp)); if (call->getFuncScope() == info.func) { call->setNoInline(); } break; } case Expression::KindOfSimpleFunctionCall: { SimpleFunctionCallPtr call(static_pointer_cast<SimpleFunctionCall>(exp)); call->addLateDependencies(ar); call->setLocalThis(info.localThis); if (call->getFuncScope() == info.func) { call->setNoInline(); } } default: break; } return exp; }
ExpressionPtr AliasManager::canonicalizeNode(ExpressionPtr e) { e->setCanonPtr(ExpressionPtr()); e->setCanonID(0); switch (e->getKindOf()) { case Expression::KindOfObjectMethodExpression: case Expression::KindOfDynamicFunctionCall: case Expression::KindOfSimpleFunctionCall: case Expression::KindOfNewObjectExpression: add(m_bucketMap[0], e); break; case Expression::KindOfListAssignment: add(m_bucketMap[0], e); break; case Expression::KindOfAssignmentExpression: { AssignmentExpressionPtr ae = spc(AssignmentExpression,e); if (e->getContext() & Expression::DeadStore) { Construct::recomputeEffects(); return ae->getValue(); } ExpressionPtr rep; int interf = findInterf(ae->getVariable(), false, rep); if (interf == SameAccess) { switch (rep->getKindOf()) { default: break; case Expression::KindOfAssignmentExpression: { AssignmentExpressionPtr a = spc(AssignmentExpression, rep); ExpressionPtr value = a->getValue(); if (a->getValue()->getContext() & Expression::RefValue) { break; } } case Expression::KindOfUnaryOpExpression: case Expression::KindOfBinaryOpExpression: rep->setContext(Expression::DeadStore); break; } } add(m_bucketMap[0], e); break; } case Expression::KindOfConstantExpression: case Expression::KindOfSimpleVariable: case Expression::KindOfDynamicVariable: case Expression::KindOfArrayElementExpression: case Expression::KindOfObjectPropertyExpression: case Expression::KindOfStaticMemberExpression: if (!(e->getContext() & (Expression::AssignmentLHS| Expression::DeepAssignmentLHS| Expression::OprLValue))) { if (!(e->getContext() & (Expression::LValue| Expression::RefValue| Expression::RefParameter| Expression::UnsetContext))) { ExpressionPtr rep; int interf = findInterf(e, true, rep); if (interf == SameAccess) { if (rep->getKindOf() == e->getKindOf()) { e->setCanonID(rep->getCanonID()); e->setCanonPtr(rep); return ExpressionPtr(); } if (rep->getKindOf() == Expression::KindOfAssignmentExpression) { ExpressionPtr rhs = spc(AssignmentExpression,rep)->getValue(); if (rhs->is(Expression::KindOfScalarExpression)) { rhs = rhs->clone(); getCanonical(rhs); return rhs; } e->setCanonPtr(rhs); } } } add(m_bucketMap[0], e); } else { getCanonical(e); } break; case Expression::KindOfBinaryOpExpression: { BinaryOpExpressionPtr bop = spc(BinaryOpExpression, e); int rop = getOpForAssignmentOp(bop->getOp()); if (rop) { ExpressionPtr lhs = bop->getExp1(); ExpressionPtr rep; if (bop->getContext() & Expression::DeadStore) { Construct::recomputeEffects(); ExpressionPtr rhs = bop->getExp2()->clone(); lhs = lhs->clone(); lhs->clearContext(Expression::LValue); lhs->clearContext(Expression::NoLValueWrapper); lhs->clearContext(Expression::OprLValue); rep = ExpressionPtr (new BinaryOpExpression(e->getLocation(), Expression::KindOfBinaryOpExpression, lhs, rhs, rop)); } else { ExpressionPtr alt; int interf = findInterf(lhs, true, alt); if (interf == SameAccess && alt->is(Expression::KindOfAssignmentExpression)) { ExpressionPtr op0 = spc(AssignmentExpression,alt)->getValue(); if (op0->is(Expression::KindOfScalarExpression)) { ExpressionPtr op1 = bop->getExp2(); ExpressionPtr rhs (new BinaryOpExpression(e->getLocation(), Expression::KindOfBinaryOpExpression, op0->clone(), op1->clone(), rop)); lhs = lhs->clone(); lhs->clearContext(Expression::OprLValue); rep = ExpressionPtr (new AssignmentExpression(e->getLocation(), Expression::KindOfAssignmentExpression, lhs, rhs, false)); } } } if (rep) { ExpressionPtr c = canonicalizeRecur(rep); return c ? c : rep; } add(m_bucketMap[0], e); } else { getCanonical(e); } break; } case Expression::KindOfUnaryOpExpression: { UnaryOpExpressionPtr uop = spc(UnaryOpExpression, e); switch (uop->getOp()) { case T_INC: case T_DEC: if (uop->getContext() & Expression::DeadStore) { Construct::recomputeEffects(); ExpressionPtr val = uop->getExpression()->clone(); val->clearContext(Expression::LValue); val->clearContext(Expression::NoLValueWrapper); val->clearContext(Expression::OprLValue); if (uop->getFront()) { ExpressionPtr inc (new ScalarExpression(uop->getLocation(), Expression::KindOfScalarExpression, T_LNUMBER, string("1"))); val = ExpressionPtr (new BinaryOpExpression(uop->getLocation(), Expression::KindOfBinaryOpExpression, val, inc, uop->getOp() == T_INC ? '+' : '-')); } ExpressionPtr r = canonicalizeRecur(val); return r ? r : val; } add(m_bucketMap[0], e); break; default: getCanonical(e); break; } break; } default: getCanonical(e); break; } return ExpressionPtr(); }