ExpressionPtr BinaryOpExpression::foldConstRightAssoc(AnalysisResultPtr ar) { ExpressionPtr optExp1; switch (m_op) { case '.': case '+': case '*': if (m_exp1->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr binOpExp = dynamic_pointer_cast<BinaryOpExpression>(m_exp1); if (binOpExp->m_op == m_op) { // turn a Op b Op c, namely (a Op b) Op c into a Op (b Op c) ExpressionPtr aExp = binOpExp->m_exp1; ExpressionPtr bExp = binOpExp->m_exp2; ExpressionPtr cExp = m_exp2; BinaryOpExpressionPtr bcExp = BinaryOpExpressionPtr(new BinaryOpExpression( getScope(), getLocation(), Expression::KindOfBinaryOpExpression, bExp, cExp, m_op)); ExpressionPtr optExp = bcExp->foldConst(ar); if (optExp) { BinaryOpExpressionPtr a_bcExp (new BinaryOpExpression(getScope(), getLocation(), Expression::KindOfBinaryOpExpression, aExp, optExp, m_op)); optExp = a_bcExp->foldConstRightAssoc(ar); if (optExp) return optExp; else return a_bcExp; } } } break; default: break; } return ExpressionPtr(); }
/** * If the binary operation is not PHP specific, but something a query * processor can handle (+ - * and so on), then rewrite the operands to * something the query processor can evaluate (such as a query parameter * references) and rewrite the entire expression to use the rewritten operands. * If the rewritten operands are the same as the original operands, just * return the expression as is. */ ExpressionPtr CaptureExtractor::rewriteBinary(BinaryOpExpressionPtr be) { assert(be != nullptr); switch (be->getOp()) { case '+': case '-': case '*': case '/': case '%': case '&': case '|': case '^': case T_IS_IDENTICAL: case T_IS_EQUAL: case '>': case '<': case T_IS_GREATER_OR_EQUAL: case T_IS_SMALLER_OR_EQUAL: case T_IS_NOT_IDENTICAL: case T_IS_NOT_EQUAL: case T_BOOLEAN_OR: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_LOGICAL_AND: case '.': break; // Could be something the query processor can handle default: return newQueryParamRef(be); } auto expr1 = be->getExp1(); auto expr2 = be->getExp2(); auto newExpr1 = rewrite(expr1); auto newExpr2 = rewrite(expr2); if (expr1 == newExpr1 && expr2 == newExpr2) return be; return std::make_shared<BinaryOpExpression>( be->getScope(), be->getRange(), newExpr1, newExpr2, be->getOp()); }
void ExpressionList::stripConcat() { ExpressionList &el = *this; for (int i = 0; i < el.getCount(); ) { ExpressionPtr &e = el[i]; if (e->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(e)); if (u->getOp() == '(') { e = u->getExpression(); } } if (e->is(Expression::KindOfBinaryOpExpression)) { BinaryOpExpressionPtr b (static_pointer_cast<BinaryOpExpression>(e)); if (b->getOp() == '.') { if (!b->getExp1()->isArray() && !b->getExp2()->isArray()) { e = b->getExp1(); el.insertElement(b->getExp2(), i + 1); continue; } } } i++; } }
// foldConst() is callable from the parse phase as well as the analysis phase. // We take advantage of this during the parse phase to reduce very simple // expressions down to a single scalar and keep the parse tree smaller, // especially in cases of long chains of binary operators. However, we limit // the effectivness of this during parse to ensure that we eliminate only // very simple scalars that don't require analysis in later phases. For now, // that's just simply scalar values. ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) { ExpressionPtr optExp; Variant v1; Variant v2; if (!m_exp2->getScalarValue(v2)) { if ((ar->getPhase() != AnalysisResult::ParseAllFiles) && m_exp1->isScalar() && m_exp1->getScalarValue(v1)) { switch (m_op) { case T_IS_IDENTICAL: case T_IS_NOT_IDENTICAL: if (v1.isNull()) { return makeIsNull(ar, getLocation(), m_exp2, m_op == T_IS_NOT_IDENTICAL); } break; case T_LOGICAL_AND: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_BOOLEAN_OR: { ExpressionPtr rep = v1.toBoolean() == (m_op == T_LOGICAL_AND || m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1; rep = ExpressionPtr( new UnaryOpExpression( getScope(), getLocation(), rep, T_BOOL_CAST, true)); rep->setActualType(Type::Boolean); return replaceValue(rep); } case '+': case '.': case '*': case '&': case '|': case '^': if (m_exp2->is(KindOfBinaryOpExpression)) { BinaryOpExpressionPtr binOpExp = dynamic_pointer_cast<BinaryOpExpression>(m_exp2); if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) { ExpressionPtr aExp = m_exp1; ExpressionPtr bExp = binOpExp->m_exp1; ExpressionPtr cExp = binOpExp->m_exp2; if (aExp->isArray() || bExp->isArray() || cExp->isArray()) { break; } m_exp1 = binOpExp = Clone(binOpExp); m_exp2 = cExp; binOpExp->m_exp1 = aExp; binOpExp->m_exp2 = bExp; if (ExpressionPtr optExp = binOpExp->foldConst(ar)) { m_exp1 = optExp; } return static_pointer_cast<Expression>(shared_from_this()); } } break; default: break; } } return ExpressionPtr(); } if (m_exp1->isScalar()) { if (!m_exp1->getScalarValue(v1)) return ExpressionPtr(); try { ScalarExpressionPtr scalar1 = dynamic_pointer_cast<ScalarExpression>(m_exp1); ScalarExpressionPtr scalar2 = dynamic_pointer_cast<ScalarExpression>(m_exp2); // Some data, like the values of __CLASS__ and friends, are not available // while we're still in the initial parse phase. if (ar->getPhase() == AnalysisResult::ParseAllFiles) { if ((scalar1 && scalar1->needsTranslation()) || (scalar2 && scalar2->needsTranslation())) { return ExpressionPtr(); } } if (!Option::WholeProgram || !Option::ParseTimeOpts) { // In the VM, don't optimize __CLASS__ if within a trait, since // __CLASS__ is not resolved yet. ClassScopeRawPtr clsScope = getOriginalClass(); if (clsScope && clsScope->isTrait()) { if ((scalar1 && scalar1->getType() == T_CLASS_C) || (scalar2 && scalar2->getType() == T_CLASS_C)) { return ExpressionPtr(); } } } Variant result; switch (m_op) { case T_LOGICAL_XOR: result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean()); break; case '|': *result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell()); break; case '&': *result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell()); break; case '^': *result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell()); break; case '.': if (v1.isArray() || v2.isArray()) { return ExpressionPtr(); } result = concat(v1.toString(), v2.toString()); break; case T_IS_IDENTICAL: result = same(v1, v2); break; case T_IS_NOT_IDENTICAL: result = !same(v1, v2); break; case T_IS_EQUAL: result = equal(v1, v2); break; case T_IS_NOT_EQUAL: result = !equal(v1, v2); break; case '<': result = less(v1, v2); break; case T_IS_SMALLER_OR_EQUAL: result = cellLessOrEqual(*v1.asCell(), *v2.asCell()); break; case '>': result = more(v1, v2); break; case T_IS_GREATER_OR_EQUAL: result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell()); break; case '+': *result.asCell() = cellAdd(*v1.asCell(), *v2.asCell()); break; case '-': *result.asCell() = cellSub(*v1.asCell(), *v2.asCell()); break; case '*': *result.asCell() = cellMul(*v1.asCell(), *v2.asCell()); break; case '/': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } *result.asCell() = cellDiv(*v1.asCell(), *v2.asCell()); break; case '%': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } *result.asCell() = cellMod(*v1.asCell(), *v2.asCell()); break; case T_SL: result = v1.toInt64() << v2.toInt64(); break; case T_SR: result = v1.toInt64() >> v2.toInt64(); break; case T_BOOLEAN_OR: result = v1.toBoolean() || v2.toBoolean(); break; case T_BOOLEAN_AND: result = v1.toBoolean() && v2.toBoolean(); break; case T_LOGICAL_OR: result = v1.toBoolean() || v2.toBoolean(); break; case T_LOGICAL_AND: result = v1.toBoolean() && v2.toBoolean(); break; case T_INSTANCEOF: { if (v2.isString()) { if (v1.isArray() && interface_supports_array(v2.getStringData())) { result = true; break; } if (v1.isString() && interface_supports_string(v2.getStringData())) { result = true; break; } if (v1.isInteger() && interface_supports_int(v2.getStringData())) { result = true; break; } if (v1.isDouble() && interface_supports_double(v2.getStringData())) { result = true; break; } } result = false; break; } default: return ExpressionPtr(); } return makeScalarExpression(ar, result); } catch (...) { } } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
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; } }
// foldConst() is callable from the parse phase as well as the analysis phase. // We take advantage of this during the parse phase to reduce very simple // expressions down to a single scalar and keep the parse tree smaller, // especially in cases of long chains of binary operators. However, we limit // the effectivness of this during parse to ensure that we eliminate only // very simple scalars that don't require analysis in later phases. For now, // that's just simply scalar values. ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) { ExpressionPtr optExp; Variant v1; Variant v2; if (!m_exp2->getScalarValue(v2)) { if ((ar->getPhase() != AnalysisResult::ParseAllFiles) && m_exp1->isScalar() && m_exp1->getScalarValue(v1)) { switch (m_op) { case T_IS_IDENTICAL: case T_IS_NOT_IDENTICAL: if (v1.isNull()) { return makeIsNull(ar, getLocation(), m_exp2, m_op == T_IS_NOT_IDENTICAL); } break; case T_LOGICAL_AND: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_BOOLEAN_OR: { ExpressionPtr rep = v1.toBoolean() == (m_op == T_LOGICAL_AND || m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1; rep = ExpressionPtr( new UnaryOpExpression( getScope(), getLocation(), rep, T_BOOL_CAST, true)); rep->setActualType(Type::Boolean); return replaceValue(rep); } case '+': case '.': case '*': case '&': case '|': case '^': if (m_exp2->is(KindOfBinaryOpExpression)) { BinaryOpExpressionPtr binOpExp = dynamic_pointer_cast<BinaryOpExpression>(m_exp2); if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) { ExpressionPtr aExp = m_exp1; ExpressionPtr bExp = binOpExp->m_exp1; ExpressionPtr cExp = binOpExp->m_exp2; m_exp1 = binOpExp = Clone(binOpExp); m_exp2 = cExp; binOpExp->m_exp1 = aExp; binOpExp->m_exp2 = bExp; if (ExpressionPtr optExp = binOpExp->foldConst(ar)) { m_exp1 = optExp; } return static_pointer_cast<Expression>(shared_from_this()); } } break; default: break; } } return ExpressionPtr(); } if (m_exp1->isScalar()) { if (!m_exp1->getScalarValue(v1)) return ExpressionPtr(); try { ScalarExpressionPtr scalar1 = dynamic_pointer_cast<ScalarExpression>(m_exp1); ScalarExpressionPtr scalar2 = dynamic_pointer_cast<ScalarExpression>(m_exp2); // Some data, like the values of __CLASS__ and friends, are not available // while we're still in the initial parse phase. if (ar->getPhase() == AnalysisResult::ParseAllFiles) { if ((scalar1 && scalar1->needsTranslation()) || (scalar2 && scalar2->needsTranslation())) { return ExpressionPtr(); } } if (!Option::WholeProgram || !Option::ParseTimeOpts) { // In the VM, don't optimize __CLASS__ if within a trait, since // __CLASS__ is not resolved yet. ClassScopeRawPtr clsScope = getOriginalClass(); if (clsScope && clsScope->isTrait()) { if ((scalar1 && scalar1->getType() == T_CLASS_C) || (scalar2 && scalar2->getType() == T_CLASS_C)) { return ExpressionPtr(); } } } Variant result; switch (m_op) { case T_LOGICAL_XOR: result = logical_xor(v1, v2); break; case '|': result = bitwise_or(v1, v2); break; case '&': result = bitwise_and(v1, v2); break; case '^': result = bitwise_xor(v1, v2); break; case '.': result = concat(v1, v2); break; case T_IS_IDENTICAL: result = same(v1, v2); break; case T_IS_NOT_IDENTICAL: result = !same(v1, v2); break; case T_IS_EQUAL: result = equal(v1, v2); break; case T_IS_NOT_EQUAL: result = !equal(v1, v2); break; case '<': result = less(v1, v2); break; case T_IS_SMALLER_OR_EQUAL: result = less_or_equal(v1, v2); break; case '>': result = more(v1, v2); break; case T_IS_GREATER_OR_EQUAL: result = more_or_equal(v1, v2); break; case '+': result = plus(v1, v2); break; case '-': result = minus(v1, v2); break; case '*': result = multiply(v1, v2); break; case '/': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } result = divide(v1, v2); break; case '%': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } result = modulo(v1, v2); break; case T_SL: result = shift_left(v1, v2); break; case T_SR: result = shift_right(v1, v2); break; case T_BOOLEAN_OR: result = v1 || v2; break; case T_BOOLEAN_AND: result = v1 && v2; break; case T_LOGICAL_OR: result = v1 || v2; break; case T_LOGICAL_AND: result = v1 && v2; break; case T_INSTANCEOF: result = false; break; default: return ExpressionPtr(); } return makeScalarExpression(ar, result); } catch (...) { } } else if (ar->getPhase() != AnalysisResult::ParseAllFiles) { switch (m_op) { case T_LOGICAL_AND: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_BOOLEAN_OR: { bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND || m_op == T_BOOLEAN_AND); ExpressionPtr rep = useFirst ? m_exp1 : m_exp2; rep = ExpressionPtr( new UnaryOpExpression( getScope(), getLocation(), rep, T_BOOL_CAST, true)); rep->setActualType(Type::Boolean); if (!useFirst) { ExpressionListPtr l( new ExpressionList( getScope(), getLocation(), ExpressionList::ListKindComma)); l->addElement(m_exp1); l->addElement(rep); l->setActualType(Type::Boolean); rep = l; } rep->setExpectedType(getExpectedType()); return replaceValue(rep); } case T_LOGICAL_XOR: case '|': case '&': case '^': case '.': case '+': case '*': optExp = foldRightAssoc(ar); if (optExp) return optExp; break; case T_IS_IDENTICAL: case T_IS_NOT_IDENTICAL: if (v2.isNull()) { return makeIsNull(ar, getLocation(), m_exp1, m_op == T_IS_NOT_IDENTICAL); } break; default: break; } } return ExpressionPtr(); }
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) { ExpressionPtr optExp; Variant v1; Variant v2; if (!m_exp2->getScalarValue(v2)) { if (m_exp1->isScalar() && m_exp1->getScalarValue(v1)) { switch (m_op) { case T_IS_IDENTICAL: case T_IS_NOT_IDENTICAL: if (v1.isNull()) { return makeIsNull(ar, getLocation(), m_exp2, m_op == T_IS_NOT_IDENTICAL); } break; case T_LOGICAL_AND: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_BOOLEAN_OR: { ExpressionPtr rep = v1.toBoolean() == (m_op == T_LOGICAL_AND || m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1; rep = ExpressionPtr( new UnaryOpExpression( getScope(), getLocation(), rep, T_BOOL_CAST, true)); rep->setActualType(Type::Boolean); return replaceValue(rep); } case '+': case '.': case '*': case '&': case '|': case '^': if (m_exp2->is(KindOfBinaryOpExpression)) { BinaryOpExpressionPtr binOpExp = dynamic_pointer_cast<BinaryOpExpression>(m_exp2); if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) { ExpressionPtr aExp = m_exp1; ExpressionPtr bExp = binOpExp->m_exp1; ExpressionPtr cExp = binOpExp->m_exp2; m_exp1 = binOpExp = Clone(binOpExp); m_exp2 = cExp; binOpExp->m_exp1 = aExp; binOpExp->m_exp2 = bExp; if (ExpressionPtr optExp = binOpExp->foldConst(ar)) { m_exp1 = optExp; } return static_pointer_cast<Expression>(shared_from_this()); } } break; default: break; } } return ExpressionPtr(); } if (m_exp1->isScalar()) { if (!m_exp1->getScalarValue(v1)) return ExpressionPtr(); try { Variant result; switch (m_op) { case T_LOGICAL_XOR: result = logical_xor(v1, v2); break; case '|': result = bitwise_or(v1, v2); break; case '&': result = bitwise_and(v1, v2); break; case '^': result = bitwise_xor(v1, v2); break; case '.': result = concat(v1, v2); break; case T_IS_IDENTICAL: result = same(v1, v2); break; case T_IS_NOT_IDENTICAL: result = !same(v1, v2); break; case T_IS_EQUAL: result = equal(v1, v2); break; case T_IS_NOT_EQUAL: result = !equal(v1, v2); break; case '<': result = less(v1, v2); break; case T_IS_SMALLER_OR_EQUAL: result = not_more(v1, v2); break; case '>': result = more(v1, v2); break; case T_IS_GREATER_OR_EQUAL: result = not_less(v1, v2); break; case '+': result = plus(v1, v2); break; case '-': result = minus(v1, v2); break; case '*': result = multiply(v1, v2); break; case '/': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } result = divide(v1, v2); break; case '%': if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) { return ExpressionPtr(); } result = modulo(v1, v2); break; case T_SL: result = shift_left(v1, v2); break; case T_SR: result = shift_right(v1, v2); break; case T_BOOLEAN_OR: result = v1 || v2; break; case T_BOOLEAN_AND: result = v1 && v2; break; case T_LOGICAL_OR: result = v1 || v2; break; case T_LOGICAL_AND: result = v1 && v2; break; case T_INSTANCEOF: result = false; break; default: return ExpressionPtr(); } return makeScalarExpression(ar, result); } catch (...) { } } else { switch (m_op) { case T_LOGICAL_AND: case T_BOOLEAN_AND: case T_LOGICAL_OR: case T_BOOLEAN_OR: { bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND || m_op == T_BOOLEAN_AND); ExpressionPtr rep = useFirst ? m_exp1 : m_exp2; rep = ExpressionPtr( new UnaryOpExpression( getScope(), getLocation(), rep, T_BOOL_CAST, true)); rep->setActualType(Type::Boolean); if (!useFirst) { ExpressionListPtr l( new ExpressionList( getScope(), getLocation(), ExpressionList::ListKindComma)); l->addElement(m_exp1); l->addElement(rep); l->setActualType(Type::Boolean); rep = l; } rep->setExpectedType(getExpectedType()); return replaceValue(rep); } case T_LOGICAL_XOR: case '|': case '&': case '^': case '.': case '+': case '*': optExp = foldRightAssoc(ar); if (optExp) return optExp; break; case T_IS_IDENTICAL: case T_IS_NOT_IDENTICAL: if (v2.isNull()) { return makeIsNull(ar, getLocation(), m_exp1, m_op == T_IS_NOT_IDENTICAL); } break; default: break; } } return ExpressionPtr(); }
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(); }