2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/compiler/analysis/alias_manager.h"
19 #include "hphp/compiler/analysis/analysis_result.h"
20 #include "hphp/compiler/analysis/function_scope.h"
21 #include "hphp/compiler/expression/expression.h"
22 #include "hphp/compiler/expression/assignment_expression.h"
23 #include "hphp/compiler/expression/array_element_expression.h"
24 #include "hphp/compiler/expression/list_assignment.h"
25 #include "hphp/compiler/expression/binary_op_expression.h"
26 #include "hphp/compiler/expression/unary_op_expression.h"
27 #include "hphp/compiler/expression/qop_expression.h"
28 #include "hphp/compiler/expression/simple_variable.h"
29 #include "hphp/compiler/expression/scalar_expression.h"
30 #include "hphp/compiler/expression/simple_function_call.h"
31 #include "hphp/compiler/expression/array_element_expression.h"
32 #include "hphp/compiler/expression/object_property_expression.h"
33 #include "hphp/compiler/expression/object_method_expression.h"
34 #include "hphp/compiler/expression/parameter_expression.h"
35 #include "hphp/compiler/expression/expression_list.h"
36 #include "hphp/compiler/expression/expression.h"
37 #include "hphp/compiler/expression/include_expression.h"
38 #include "hphp/compiler/expression/closure_expression.h"
39 #include "hphp/compiler/expression/yield_expression.h"
40 #include "hphp/compiler/statement/statement.h"
41 #include "hphp/compiler/statement/statement_list.h"
42 #include "hphp/compiler/statement/catch_statement.h"
43 #include "hphp/compiler/statement/method_statement.h"
44 #include "hphp/compiler/statement/block_statement.h"
45 #include "hphp/compiler/statement/if_statement.h"
46 #include "hphp/compiler/statement/if_branch_statement.h"
47 #include "hphp/compiler/statement/switch_statement.h"
48 #include "hphp/compiler/statement/break_statement.h"
49 #include "hphp/compiler/statement/return_statement.h"
50 #include "hphp/compiler/statement/loop_statement.h"
51 #include "hphp/compiler/statement/foreach_statement.h"
52 #include "hphp/compiler/statement/for_statement.h"
53 #include "hphp/compiler/statement/while_statement.h"
54 #include "hphp/compiler/statement/do_statement.h"
55 #include "hphp/compiler/statement/exp_statement.h"
56 #include "hphp/compiler/statement/echo_statement.h"
57 #include "hphp/compiler/statement/try_statement.h"
58 #include "hphp/compiler/statement/global_statement.h"
59 #include "hphp/compiler/statement/static_statement.h"
60 #include "hphp/compiler/analysis/control_flow.h"
61 #include "hphp/compiler/analysis/variable_table.h"
62 #include "hphp/compiler/analysis/data_flow.h"
63 #include "hphp/compiler/analysis/dictionary.h"
64 #include "hphp/compiler/analysis/expr_dict.h"
65 #include "hphp/compiler/analysis/live_dict.h"
66 #include "hphp/compiler/analysis/ref_dict.h"
68 #include "hphp/runtime/base/builtin_functions.h"
70 #include "hphp/util/parser/hphp.tab.hpp"
71 #include "hphp/util/parser/location.h"
72 #include "hphp/util/util.h"
74 #define spc(T,p) boost::static_pointer_cast<T>(p)
75 #define dpc(T,p) boost::dynamic_pointer_cast<T>(p)
80 ///////////////////////////////////////////////////////////////////////////////
82 AliasManager::AliasManager(int opt
) :
83 m_bucketList(0), m_nextID(1), m_changes(0), m_replaced(0),
84 m_wildRefs(false), m_nrvoFix(0), m_inCall(0), m_inlineAsExpr(true),
85 m_noAdd(false), m_preOpt(opt
<0), m_postOpt(opt
>0),
86 m_cleared(false), m_inPseudoMain(false), m_genAttrs(false),
87 m_hasDeadStore(false), m_hasChainRoot(false),
88 m_hasTypeAssertions(false), m_graph(0), m_exprIdx(-1) {
91 AliasManager::~AliasManager() {
95 bool AliasManager::parseOptimizations(const std::string
&optimizations
,
99 while ((pos
= optimizations
.find_first_not_of(" ,", pos
)) !=
101 size_t end
= optimizations
.find_first_of(" ,", pos
);
102 string opt
= optimizations
.substr(pos
, end
- pos
);
104 if (opt
.substr(0, 3) == "no-") {
109 if (opt
== "deadcode") {
110 Option::EliminateDeadCode
= val
;
111 } else if (opt
== "localcopy") {
112 Option::LocalCopyProp
= val
;
113 } else if (opt
== "copyprop") {
114 Option::CopyProp
= val
;
115 } else if (opt
== "string") {
116 Option::StringLoopOpts
= val
;
117 } else if (opt
== "inline") {
118 Option::AutoInline
= val
? 1 : -1;
119 } else if (opt
== "cflow") {
120 Option::ControlFlow
= val
;
121 } else if (opt
== "coalesce") {
122 Option::VariableCoalescing
= val
;
123 } else if (val
&& (opt
== "all" || opt
== "none")) {
125 Option::EliminateDeadCode
= val
;
126 Option::LocalCopyProp
= val
;
127 Option::AutoInline
= val
? 1 : -1;
128 Option::ControlFlow
= val
;
129 Option::CopyProp
= val
;
131 errs
= "Unknown optimization: " + opt
;
135 if (end
== string::npos
) {
144 ExpressionPtr
BucketMapEntry::find(ExpressionPtr e
) {
145 ExpressionPtrList::iterator it
= m_exprs
.begin();
146 while (it
!= m_exprs
.end()) {
147 ExpressionPtr c
= *it
;
148 if (e
->canonCompare(c
)) {
154 return ExpressionPtr();
157 void BucketMapEntry::add(ExpressionPtr e
) {
158 m_exprs
.push_back(e
);
162 void BucketMapEntry::clear() {
168 void BucketMapEntry::beginScope() {
169 m_stack
.push_back(m_num
);
172 void BucketMapEntry::endScope() {
174 if (m_stack
.size()) {
179 void BucketMapEntry::resetScope() {
180 if (!m_stack
.size()) {
184 m_num
= m_stack
.back();
185 always_assert(m_exprs
.size() >= m_num
);
186 m_exprs
.resize(m_num
);
190 bool BucketMapEntry::isSubLast(ExpressionPtr e
) {
191 ExpressionPtrList::reverse_iterator it
= rbegin(), end
= rend();
193 ExpressionPtr t
= *it
++;
194 if (t
== e
) return true;
195 if (t
->hasSubExpr(e
)) return true;
196 if (t
->is(Expression::KindOfSimpleVariable
)) continue;
197 if (!t
->is(Expression::KindOfScalarExpression
)) break;
198 ScalarExpressionPtr se
= spc(ScalarExpression
, t
);
199 const std::string
&s
= se
->getString();
200 if (s
!= "begin" && s
!= "end") break;
205 void BucketMapEntry::stash(size_t from
, ExpressionPtrList
&to
) {
206 ExpressionPtrList::iterator it
= m_exprs
.begin(), end
= m_exprs
.end();
209 always_assert(it
!= end
);
213 ExpressionPtr t
= *it
;
215 to
.insert(to
.end(), t
);
216 it
= m_exprs
.erase(it
);
220 void BucketMapEntry::import(ExpressionPtrList
&from
) {
221 m_num
+= from
.size();
222 m_exprs
.splice(m_exprs
.end(), from
);
225 void AliasManager::add(BucketMapEntry
&em
, ExpressionPtr e
) {
226 if (!m_noAdd
) em
.add(e
);
227 if (!m_genAttrs
) e
->setCanonID(m_nextID
++);
230 bool AliasManager::insertForDict(ExpressionPtr e
) {
231 ExpressionPtr c
= getCanonical(e
);
232 if (c
== e
) return true;
233 e
->setCanonID(c
->getCanonID());
237 ExpressionPtr
AliasManager::getCanonical(ExpressionPtr e
) {
238 unsigned val
= (e
->getCanonHash() % MaxBuckets
);
240 BucketMapEntry
&em
= m_bucketMap
[val
];
241 em
.link(m_bucketList
);
243 ExpressionPtr c
= em
.find(e
);
248 if (!m_genAttrs
) e
->setCanonPtr(ExpressionPtr());
249 } else if (!m_genAttrs
) {
250 e
->setCanonID(c
->getCanonID());
257 void AliasManager::clear() {
258 m_accessList
.clear();
265 void AliasManager::beginScope() {
267 ExpressionPtr
e(new ScalarExpression(BlockScopePtr(), LocationPtr(),
268 T_STRING
, string("begin")));
270 m_stack
.push_back(CondStackElem(m_accessList
.size()));
271 m_accessList
.beginScope();
272 if (BucketMapEntry
*tail
= m_bucketList
) {
273 BucketMapEntry
*bm
= tail
;
276 } while ((bm
= bm
->next()) != tail
);
280 void AliasManager::mergeScope() {
282 if (m_stack
.size()) {
283 CondStackElem
&cs
= m_stack
.back();
284 BucketMapEntry
&bm
= m_accessList
;
285 bm
.stash(cs
.m_size
, cs
.m_exprs
);
291 void AliasManager::endScope() {
295 m_accessList
.endScope();
296 if (BucketMapEntry
*tail
= m_bucketList
) {
297 BucketMapEntry
*bm
= tail
;
300 } while ((bm
= bm
->next()) != tail
);
303 if (m_stack
.size()) {
304 CondStackElem
&cs
= m_stack
.back();
305 BucketMapEntry
&bm
= m_accessList
;
306 bm
.import(cs
.m_exprs
);
308 e(new ScalarExpression(BlockScopePtr(), LocationPtr(),
309 T_STRING
, string("end")));
315 void AliasManager::resetScope() {
318 m_accessList
.resetScope();
319 if (BucketMapEntry
*tail
= m_bucketList
) {
320 BucketMapEntry
*bm
= tail
;
323 } while ((bm
= bm
->next()) != tail
);
327 void AliasManager::dumpAccessChain() {
328 BucketMapEntry
&lvs
= m_accessList
;
329 ExpressionPtrList::reverse_iterator it
= lvs
.rbegin(), end
= lvs
.rend();
331 if (isInExpression()) {
332 std::cout
<< "m_exprIdx: " << m_exprIdx
<< std::endl
;
333 std::cout
<< "parent: "; m_exprParent
->dumpNode(0, m_arp
);
335 std::cout
<< "Not in expression" << std::endl
;
339 ExpressionPtr e
= *it
;
345 bool AliasManager::couldBeAliased(SimpleVariablePtr sv
) {
346 if (m_wildRefs
) return true;
347 if (!sv
->couldBeAliased()) return false;
348 if (m_inPseudoMain
) return true;
349 int context
= sv
->getContext();
350 if ((context
& Expression::Declaration
) ==
351 Expression::Declaration
/* global declaration */ ||
352 (context
& Expression::RefAssignmentLHS
) ||
353 (context
& (Expression::LValue
|Expression::UnsetContext
)) ==
354 (Expression::LValue
|Expression::UnsetContext
)) {
356 All of these are effectively reference assignments, so the only
357 thing that interferes is an exact match.
364 static bool canonCompare(ExpressionPtr e1
, ExpressionPtr e2
) {
366 e1
->hasContext(Expression::ExistContext
) ==
367 e2
->hasContext(Expression::ExistContext
) &&
368 e1
->canonCompare(e2
);
371 static bool compareArrays(ArrayElementExpressionPtr e1
,
372 ArrayElementExpressionPtr e2
) {
373 if (!e1
->getOffset() || !e2
->getOffset() ||
374 e1
->getOffset()->getCanonID() != e2
->getOffset()->getCanonID()) {
377 always_assert(e1
->getOffset()->getCanonID() != 0);
379 if (e1
->getVariable()->getCanonID() == e2
->getVariable()->getCanonID() &&
380 e1
->getVariable()->getCanonID() != 0) {
384 if (e1
->getVariable()->getCanonLVal() == e2
->getVariable() ||
385 e2
->getVariable()->getCanonLVal() == e1
->getVariable()) {
392 int AliasManager::testAccesses(ExpressionPtr e1
, ExpressionPtr e2
,
393 bool forLval
/* = false */) {
394 Expression::KindOf k1
= e1
->getKindOf(), k2
= e2
->getKindOf();
397 case Expression::KindOfConstantExpression
:
398 if (canonCompare(e1
, e2
)) return SameAccess
;
400 case Expression::KindOfObjectMethodExpression
:
401 case Expression::KindOfDynamicFunctionCall
:
402 case Expression::KindOfSimpleFunctionCall
:
403 case Expression::KindOfNewObjectExpression
:
406 return DisjointAccess
;
410 case Expression::KindOfArrayElementExpression
:
411 if (k2
== Expression::KindOfSimpleVariable
||
412 k2
== Expression::KindOfDynamicVariable
||
413 k2
== Expression::KindOfConstantExpression
) {
417 if (canonCompare(e1
, e2
)) return SameAccess
;
419 if (k2
!= Expression::KindOfArrayElementExpression
) {
420 if (forLval
&& !e1
->hasContext(Expression::LValue
)) {
421 return DisjointAccess
;
427 ArrayElementExpressionPtr
p1(spc(ArrayElementExpression
, e1
));
428 ArrayElementExpressionPtr
p2(spc(ArrayElementExpression
, e2
));
429 if (compareArrays(p1
, p2
)) return SameAccess
;
431 if (!forLval
) return InterfAccess
;
433 // forLval alias checking
435 // e1 and e2 are both array elements, where e2 is testing
436 // against e1 (e1 is ahead in the chain)
438 if (!p2
->getVariable()->is(Expression::KindOfSimpleVariable
)) {
441 SimpleVariablePtr
sv2(spc(SimpleVariable
, p2
->getVariable()));
442 if (couldBeAliased(sv2
)) return InterfAccess
;
444 // e2 looks like ($a[...]) now, and $a is not referenced
445 // so the only way e1 would interfere (in an lvalue sense)
446 // is if e1 looked also like ($a[...])
448 if (!p1
->getVariable()->is(Expression::KindOfSimpleVariable
)) {
449 if (p1
->getVariable()->is(Expression::KindOfDynamicVariable
)) {
452 return DisjointAccess
;
454 SimpleVariablePtr
sv1(spc(SimpleVariable
, p1
->getVariable()));
456 // make sure the variables refer to the same thing by chasing
458 ExpressionPtr
p(sv2
->getCanonLVal());
459 while (p
&& p
!= sv1
) p
= p
->getCanonLVal();
460 if (!p
) return DisjointAccess
;
462 // make sure the offsets refer to the same *value* by comparing
464 if (!p1
->getOffset() || !p2
->getOffset()) return InterfAccess
;
465 return p1
->getOffset()->getCanonID() == p2
->getOffset()->getCanonID() ?
466 SameAccess
: InterfAccess
;
469 case Expression::KindOfStaticMemberExpression
:
470 if (k2
== Expression::KindOfSimpleVariable
||
471 k2
== Expression::KindOfConstantExpression
) {
474 return canonCompare(e1
, e2
) ?
475 SameAccess
: InterfAccess
;
477 case Expression::KindOfObjectPropertyExpression
:
478 if (k2
== Expression::KindOfSimpleVariable
||
479 k2
== Expression::KindOfConstantExpression
) {
484 case Expression::KindOfDynamicVariable
:
485 if (k2
== Expression::KindOfSimpleVariable
||
486 k2
== Expression::KindOfConstantExpression
) {
490 return canonCompare(e1
, e2
) ?
491 SameAccess
: InterfAccess
;
493 case Expression::KindOfSimpleVariable
:
495 if (k2
== Expression::KindOfConstantExpression
) {
496 return DisjointAccess
;
498 SimpleVariablePtr sv1
= spc(SimpleVariable
, e1
);
500 case Expression::KindOfSimpleVariable
:
502 SimpleVariablePtr sv2
= spc(SimpleVariable
, e2
);
503 if (sv1
->getName() == sv2
->getName()) {
504 if (sv1
->SimpleVariable::isThis() &&
505 sv1
->hasContext(Expression::ObjectContext
) !=
506 sv2
->hasContext(Expression::ObjectContext
) &&
507 m_variables
->getAttribute(
508 VariableTable::ContainsLDynamicVariable
)) {
510 * $this not in object context may not be the same as
511 * $this in object context if there have been writes
512 * through a variable table
519 if (couldBeAliased(sv1
) && couldBeAliased(sv2
)) {
523 return DisjointAccess
;
525 case Expression::KindOfDynamicVariable
:
528 case Expression::KindOfArrayElementExpression
:
529 if (couldBeAliased(sv1
)) {
532 return DisjointAccess
;
534 case Expression::KindOfSimpleFunctionCall
: {
535 SimpleFunctionCallPtr
call(spc(SimpleFunctionCall
, e2
));
536 if (call
->readsLocals() || call
->writesLocals()) {
541 case Expression::KindOfIncludeExpression
: {
544 case Expression::KindOfStaticMemberExpression
:
545 case Expression::KindOfObjectPropertyExpression
:
547 if (couldBeAliased(sv1
)) {
550 return DisjointAccess
;
552 // mustnt get here (we would loop forever).
555 case Expression::KindOfSimpleFunctionCall
:
556 case Expression::KindOfIncludeExpression
:
557 if (k2
== Expression::KindOfSimpleVariable
) {
564 ExpressionPtr t
= e1
;
568 k2
= e2
->getKindOf();
572 static bool isReadOnlyAccess(ExpressionPtr e
) {
573 if (e
->getContext() & (Expression::UnsetContext
|
574 Expression::RefValue
|
575 Expression::RefParameter
|
576 Expression::LValue
)) {
579 switch (e
->getKindOf()) {
580 case Expression::KindOfConstantExpression
:
581 case Expression::KindOfSimpleVariable
:
582 case Expression::KindOfArrayElementExpression
:
583 case Expression::KindOfDynamicVariable
:
590 static void updateDepthAndFlags(ExpressionPtr e
, int &depth
, int &flags
) {
591 ScalarExpressionPtr se
= spc(ScalarExpression
, e
);
592 const std::string
&s
= se
->getString();
595 } else if (s
== "end") {
597 } else if (s
== "io") {
598 flags
|= Expression::IOEffect
;
604 void AliasManager::cleanRefs(ExpressionPtr e
,
605 ExpressionPtrList::reverse_iterator it
,
606 ExpressionPtrList::reverse_iterator
&end
,
608 if (e
->is(Expression::KindOfUnaryOpExpression
) &&
609 e
->getLocalEffects() == Expression::UnknownEffect
) {
612 if (e
->is(Expression::KindOfAssignmentExpression
) ||
613 e
->is(Expression::KindOfBinaryOpExpression
) ||
614 e
->is(Expression::KindOfUnaryOpExpression
)) {
615 ExpressionPtr var
= e
->getStoreVariable();
616 if (var
->is(Expression::KindOfSimpleVariable
) &&
617 !(var
->getContext() & Expression::RefAssignmentLHS
)) {
618 SimpleVariablePtr
sv(spc(SimpleVariable
, var
));
619 if (sv
->getSymbol() && sv
->getSymbol()->isReferenced()) {
626 The $q from the return interferes with "$t = 0;", so we
627 remove "$t = 0" from the list (meaning that we /wont/ kill it).
628 But $q does not interfere with "$t = &$q". So when we remove
629 "$t = 0", we also have to remove any reference assignments
633 bool pIsLoad
= false;
636 ExpressionPtr p
= *it
;
637 if (p
->is(Expression::KindOfScalarExpression
)) {
638 checkInterf(var
, p
, pIsLoad
, depth
, effects
);
639 if (depth
< 0) return;
640 } else if (p
->is(Expression::KindOfAssignmentExpression
) ||
641 (p
->is(Expression::KindOfSimpleVariable
) &&
642 (p
->hasAllContext(Expression::Declaration
) ||
643 p
->hasAllContext(Expression::LValue
|
644 Expression::UnsetContext
)))) {
645 if (checkInterf(var
, p
, pIsLoad
, depth
, effects
) == SameAccess
) {
646 m_accessList
.erase(it
, end
);
657 void AliasManager::cleanInterf(ExpressionPtr load
,
658 ExpressionPtrList::reverse_iterator it
,
659 ExpressionPtrList::reverse_iterator
&end
,
662 ExpressionPtr e
= *it
;
663 bool eIsLoad
= false;
665 int a
= checkInterf(load
, e
, eIsLoad
, depth
, effects
);
666 if (a
!= DisjointAccess
) {
667 if (a
== NotAccess
) {
668 if (depth
< 0) return;
669 } else if (!eIsLoad
&& !dpc(FunctionCall
, e
)) {
670 cleanRefs(e
, it
, end
, depth
);
671 m_accessList
.erase(it
, end
);
679 bool AliasManager::okToKill(ExpressionPtr ep
, bool killRef
) {
680 if (ep
&& ep
->isNoRemove()) return false;
681 if (ep
&& ep
->is(Expression::KindOfSimpleVariable
)) {
682 return spc(SimpleVariable
, ep
)->canKill(killRef
);
687 static int getOpForAssignmentOp(int op
) {
689 case T_PLUS_EQUAL
: return '+';
690 case T_MINUS_EQUAL
: return '-';
691 case T_MUL_EQUAL
: return '*';
692 case T_DIV_EQUAL
: return '/';
693 case T_CONCAT_EQUAL
: return '.';
694 case T_MOD_EQUAL
: return '%';
695 case T_AND_EQUAL
: return '&';
696 case T_OR_EQUAL
: return '|';
697 case T_XOR_EQUAL
: return '^';
698 case T_SL_EQUAL
: return T_SL
;
699 case T_SR_EQUAL
: return T_SR
;
704 void AliasManager::killLocals() {
705 BucketMapEntry
&lvs
= m_accessList
;
706 ExpressionPtrList::reverse_iterator it
= lvs
.rbegin(), end
= lvs
.rend();
709 int emask
= (Expression::IOEffect
|
710 Expression::CanThrow
|
711 Expression::AccessorEffect
|
712 Expression::OtherEffect
);
715 ExpressionPtr e
= *it
;
716 switch (e
->getKindOf()) {
717 case Expression::KindOfScalarExpression
:
718 updateDepthAndFlags(e
, depth
, effects
);
725 case Expression::KindOfListAssignment
:
726 if (!(effects
& emask
)) {
727 ListAssignmentPtr la
= spc(ListAssignment
, e
);
728 ExpressionList
&lhs
= *la
->getVariables().get();
729 for (int i
= lhs
.getCount(); i
--; ) {
730 if (okToKill(lhs
[i
], false)) {
737 case Expression::KindOfAssignmentExpression
:
738 if (!(effects
& emask
)) {
739 AssignmentExpressionPtr
ae(spc(AssignmentExpression
, e
));
740 if (okToKill(ae
->getVariable(),
741 ae
->getValue()->getContext() & Expression::RefValue
)) {
742 e
->setContext(Expression::DeadStore
);
746 cleanRefs(e
, it
, end
, depth
);
749 case Expression::KindOfBinaryOpExpression
:
750 if (!(effects
& emask
) &&
751 getOpForAssignmentOp(spc(BinaryOpExpression
, e
)->getOp())) {
752 if (okToKill(spc(BinaryOpExpression
, e
)->getExp1(), false)) {
753 e
->setContext(Expression::DeadStore
);
759 cleanInterf(spc(BinaryOpExpression
, e
)->getExp1(), ++it
, end
, depth
);
762 case Expression::KindOfUnaryOpExpression
:
763 if (e
->getLocalEffects() == Expression::UnknownEffect
) goto kill_it
;
764 cleanInterf(spc(UnaryOpExpression
, e
)->getExpression(),
768 case Expression::KindOfSimpleVariable
:
769 case Expression::KindOfObjectPropertyExpression
:
770 case Expression::KindOfDynamicVariable
:
771 case Expression::KindOfArrayElementExpression
:
772 case Expression::KindOfStaticMemberExpression
:
773 if (e
->hasAllContext(Expression::LValue
| Expression::UnsetContext
) ||
774 e
->hasAllContext(Expression::Declaration
)) {
775 if (!(effects
& emask
) && okToKill(e
, true)) {
776 bool ok
= (m_postOpt
|| !e
->is(Expression::KindOfSimpleVariable
));
778 Symbol
*sym
= spc(SimpleVariable
,e
)->getSymbol();
781 (sym
->isGlobal() && !e
->hasContext(Expression::UnsetContext
)) ||
782 (!sym
->isNeeded() && !sym
->isUsed());
785 e
->setReplacement(e
->makeConstant(m_arp
, "null"));
789 effects
|= Expression::UnknownEffect
;
793 cleanInterf(e
, ++it
, end
, depth
);
798 effects
|= e
->getContainedEffects();
802 effects
|= e
->getContainedEffects();
807 int AliasManager::checkInterf(ExpressionPtr rv
, ExpressionPtr e
,
808 bool &isLoad
, int &depth
, int &effects
,
809 bool forLval
/* = false */) {
811 switch (e
->getKindOf()) {
812 case Expression::KindOfScalarExpression
:
814 updateDepthAndFlags(e
, depth
, effects
);
818 case Expression::KindOfObjectMethodExpression
:
819 case Expression::KindOfDynamicFunctionCall
:
820 case Expression::KindOfSimpleFunctionCall
:
821 case Expression::KindOfNewObjectExpression
:
822 case Expression::KindOfIncludeExpression
:
824 return testAccesses(rv
, e
, forLval
);
826 case Expression::KindOfListAssignment
: {
828 ListAssignmentPtr la
= spc(ListAssignment
, e
);
829 ExpressionList
&lhs
= *la
->getVariables().get();
830 for (int i
= lhs
.getCount(); i
--; ) {
831 ExpressionPtr ep
= lhs
[i
];
833 if (ep
->is(Expression::KindOfListAssignment
)) {
834 if (checkInterf(rv
, ep
, isLoad
, depth
, effects
, forLval
) !=
838 } else if (testAccesses(ep
, rv
, forLval
) != DisjointAccess
) {
846 case Expression::KindOfObjectPropertyExpression
:
847 case Expression::KindOfConstantExpression
:
848 case Expression::KindOfSimpleVariable
:
849 case Expression::KindOfDynamicVariable
:
850 case Expression::KindOfArrayElementExpression
:
851 case Expression::KindOfStaticMemberExpression
: {
852 int m
= e
->getContext() &
854 Expression::Declaration
|
855 Expression::UnsetContext
);
856 isLoad
= !(m
& Expression::LValue
) || m
== Expression::LValue
;
857 return testAccesses(e
, rv
, forLval
);
860 case Expression::KindOfUnaryOpExpression
:
861 if (e
->getLocalEffects() == Expression::UnknownEffect
) {
866 case Expression::KindOfAssignmentExpression
:
867 case Expression::KindOfBinaryOpExpression
: {
869 ExpressionPtr var
= e
->getStoreVariable();
870 int access
= testAccesses(var
, rv
, forLval
);
871 if (access
== SameAccess
) {
872 // An assignment to something that might be visible from
873 // another scope, and that might contain an object, could
874 // end up with some other value (due to a destructor running)
876 if (var
->getKindOf() != Expression::KindOfSimpleVariable
) {
879 SimpleVariablePtr sv
= static_pointer_cast
<SimpleVariable
>(var
);
880 if (sv
->couldBeAliased() &&
881 (sv
->isNeededValid() ? sv
->isNeeded() :
882 !sv
->getSymbol() || sv
->getSymbol()->isNeeded())) {
893 return DisjointAccess
;
896 int AliasManager::checkAnyInterf(ExpressionPtr e1
, ExpressionPtr e2
,
897 bool &isLoad
, int &depth
, int &effects
,
898 bool forLval
/* = false */) {
899 switch (e1
->getKindOf()) {
900 case Expression::KindOfListAssignment
: {
901 ListAssignmentPtr la
= spc(ListAssignment
, e1
);
902 ExpressionList
&lhs
= *la
->getVariables().get();
903 for (int i
= lhs
.getCount(); i
--; ) {
904 ExpressionPtr ep
= lhs
[i
];
905 if (ep
&& checkAnyInterf(ep
, e2
, isLoad
, depth
, effects
, forLval
) !=
911 return DisjointAccess
;
913 case Expression::KindOfAssignmentExpression
:
914 case Expression::KindOfBinaryOpExpression
:
915 case Expression::KindOfUnaryOpExpression
:
916 if (e1
->getLocalEffects() == Expression::UnknownEffect
) {
920 e1
= e1
->getStoreVariable();
921 if (!e1
|| !e1
->hasContext(Expression::OprLValue
)) return DisjointAccess
;
927 return checkInterf(e1
, e2
, isLoad
, depth
, effects
, forLval
);
930 int AliasManager::findInterf0(
931 ExpressionPtr rv
, bool isLoad
,
933 ExpressionPtrList::reverse_iterator begin
,
934 ExpressionPtrList::reverse_iterator end
,
935 int *flags
/* = 0 */,
936 bool allowLval
/* = false */, bool forLval
/* = false */,
937 int depth
/* = 0 */, int min_depth
/* = 0 */,
938 int max_depth
/* = 0 */) {
941 ExpressionPtrList::reverse_iterator it
= begin
;
943 bool unset_simple
= !isLoad
&&
944 rv
->hasAllContext(Expression::UnsetContext
| Expression::LValue
) &&
945 rv
->is(Expression::KindOfSimpleVariable
) &&
946 (!m_inPseudoMain
|| spc(SimpleVariable
, rv
)->isHidden());
948 bool hasStash
= false;
949 ExpressionPtrList::reverse_iterator stash
;
950 int stash_depth
= 0, stash_min_depth
= 0, stash_max_depth
= 0;
952 for (; it
!= end
; ++it
) {
953 ExpressionPtr e
= *it
;
954 if (e
->getContext() & Expression::DeadStore
) continue;
955 bool eIsLoad
= false;
957 int a
= checkInterf(rv
, e
, eIsLoad
, depth
, effects
, forLval
);
958 if (a
!= DisjointAccess
) {
959 if (a
== NotAccess
) {
960 if (effects
& Expression::IOEffect
) {
961 int effect
= rv
->getLocalEffects();
962 if (effect
& (Expression::IOEffect
|
963 Expression::CanThrow
|
964 Expression::AccessorEffect
|
965 Expression::OtherEffect
)) {
968 } else if (depth
< min_depth
) {
970 } else if (depth
> max_depth
) {
974 if (a
== InterfAccess
&&
975 rv
->is(Expression::KindOfArrayElementExpression
) &&
976 e
->hasContext(Expression::AccessContext
)) {
977 ExpressionPtr t
= rv
;
979 t
= spc(ArrayElementExpression
, t
)->getVariable();
981 } while (t
->is(Expression::KindOfArrayElementExpression
));
982 if (t
== e
) continue;
985 if (a
== InterfAccess
) {
990 } else if (a
== SameAccess
&& rep
) {
991 if (!e
->is(Expression::KindOfSimpleVariable
) ||
992 !e
->hasAllContext(Expression::UnsetContext
|
993 Expression::LValue
)) {
998 if (a
== SameAccess
) {
1001 if (depth
> min_depth
) *flags
|= NoCopyProp
;
1002 if (min_depth
< 0) *flags
|= NoDeadStore
;
1003 } else if (isLoad
) {
1004 // The value of an earlier load is available
1005 // if it dominates this one
1006 if (depth
> min_depth
) {
1010 // The assignment definitely hits the load
1011 // if it post-dominates it.
1012 if (min_depth
< 0) {
1017 if (a
!= SameAccess
&& eIsLoad
&& isLoad
&& isReadOnlyAccess(e
)) {
1018 if (!hasStash
&& !forLval
&& allowLval
) {
1019 // stash the state away so we can pick up here if we need to
1022 stash_depth
= depth
;
1023 stash_min_depth
= min_depth
;
1024 stash_max_depth
= max_depth
;
1029 if (!forLval
&& allowLval
&& a
!= SameAccess
) {
1033 stash
, end
, flags
, allowLval
, true,
1034 stash_depth
, stash_min_depth
,
1038 // try this node again
1042 if (a
== SameAccess
&& forLval
) a
= SameLValueAccess
;
1052 stash
, end
, flags
, allowLval
, true,
1053 stash_depth
, stash_min_depth
,
1057 return DisjointAccess
;
1060 int AliasManager::findInterf(ExpressionPtr rv
, bool isLoad
,
1061 ExpressionPtr
&rep
, int *flags
/* = 0 */,
1062 bool allowLval
/* = false */) {
1063 BucketMapEntry
&lvs
= m_accessList
;
1064 return findInterf0(rv
, isLoad
, rep
, lvs
.rbegin(), lvs
.rend(),
1068 ExpressionPtr
AliasManager::canonicalizeNonNull(ExpressionPtr e
) {
1069 ExpressionPtr r
= canonicalizeNode(e
);
1073 ExpressionPtr
AliasManager::canonicalizeRecurNonNull(ExpressionPtr e
) {
1074 ExpressionPtr r
= canonicalizeRecur(e
);
1078 static bool sameExpr(ExpressionPtr e1
, ExpressionPtr e2
) {
1079 if (e1
== e2
) return true;
1081 e2
= e2
->getCanonPtr();
1083 if (e2
== e1
) return true;
1088 void AliasManager::setCanonPtrForArrayCSE(
1090 ExpressionPtr rep
) {
1093 if (e
->is(Expression::KindOfArrayElementExpression
)) {
1094 // e is an array access in rvalue context,
1095 // need to switch on rep
1097 switch (rep
->getKindOf()) {
1098 case Expression::KindOfAssignmentExpression
:
1099 case Expression::KindOfBinaryOpExpression
:
1100 case Expression::KindOfUnaryOpExpression
:
1101 rep0
= rep
->getStoreVariable();
1103 case Expression::KindOfListAssignment
:
1111 if (rep0
&& rep0
->is(Expression::KindOfArrayElementExpression
)) {
1112 e
->setCanonPtr(rep0
);
1113 ExpressionPtr
match(e
->getNextCanonCsePtr());
1114 if (match
&& !match
->isChainRoot()) {
1115 ExpressionPtr
matchNext(match
->getNextCanonCsePtr());
1117 // make match a new CSE chain root
1118 match
->setChainRoot();
1119 m_hasChainRoot
= true;
1126 void AliasManager::processAccessChain(ExpressionPtr e
) {
1128 if (!e
->is(Expression::KindOfObjectPropertyExpression
) &&
1129 !e
->is(Expression::KindOfArrayElementExpression
)) {
1132 for (int i
= 0, n
= e
->getKidCount(); i
< n
; ++i
) {
1133 ExpressionPtr
kid(e
->getNthExpr(i
));
1134 if (kid
&& kid
->hasContext(Expression::AccessContext
)) {
1135 processAccessChain(kid
);
1136 ExpressionPtr
rep(canonicalizeNode(kid
, true));
1138 e
->setNthKid(i
, rep
);
1139 e
->recomputeEffects();
1147 void AliasManager::processAccessChainLA(ListAssignmentPtr la
) {
1148 ExpressionList
&lhs
= *la
->getVariables().get();
1149 for (int i
= lhs
.getCount(); i
--; ) {
1150 ExpressionPtr ep
= lhs
[i
];
1152 if (ep
->is(Expression::KindOfListAssignment
)) {
1153 processAccessChainLA(spc(ListAssignment
, ep
));
1155 processAccessChain(ep
);
1156 add(m_accessList
, ep
);
1162 ExpressionPtr
AliasManager::canonicalizeNode(
1163 ExpressionPtr e
, bool doAccessChains
/* = false */) {
1164 if (e
->isVisited()) return ExpressionPtr();
1165 if ((e
->getContext() & (Expression::AssignmentLHS
|
1166 Expression::OprLValue
)) ||
1167 (!doAccessChains
&& e
->hasContext(Expression::AccessContext
))) {
1170 if (m_preOpt
) ret
= e
->preOptimize(m_arp
);
1171 if (m_postOpt
) ret
= e
->postOptimize(m_arp
);
1173 return canonicalizeRecurNonNull(ret
);
1176 e
->setCanonPtr(ExpressionPtr());
1178 return ExpressionPtr();
1182 switch (e
->getKindOf()) {
1183 case Expression::KindOfAssignmentExpression
: {
1184 case Expression::KindOfBinaryOpExpression
:
1185 case Expression::KindOfUnaryOpExpression
:
1186 ExpressionPtr var
= e
->getStoreVariable();
1187 if (var
&& var
->getContext() & (Expression::AssignmentLHS
|
1188 Expression::OprLValue
)) {
1189 processAccessChain(var
);
1193 case Expression::KindOfListAssignment
:
1194 processAccessChainLA(spc(ListAssignment
,e
));
1201 if (!m_noAdd
&& !doAccessChains
) {
1202 if (m_preOpt
) ret
= e
->preOptimize(m_arp
);
1203 if (m_postOpt
) ret
= e
->postOptimize(m_arp
);
1205 return canonicalizeRecurNonNull(ret
);
1210 e
->clearLocalExprAltered();
1211 e
->setCanonPtr(ExpressionPtr());
1212 e
->clearChainRoot();
1215 switch (e
->getKindOf()) {
1216 case Expression::KindOfObjectMethodExpression
:
1217 case Expression::KindOfDynamicFunctionCall
:
1218 case Expression::KindOfSimpleFunctionCall
:
1219 case Expression::KindOfNewObjectExpression
:
1220 case Expression::KindOfIncludeExpression
:
1221 case Expression::KindOfListAssignment
:
1222 markAllLocalExprAltered(e
);
1223 add(m_accessList
, e
);
1226 case Expression::KindOfAssignmentExpression
: {
1227 AssignmentExpressionPtr ae
= spc(AssignmentExpression
,e
);
1228 if (e
->hasContext(Expression::DeadStore
)) {
1229 e
->recomputeEffects();
1230 return ae
->replaceValue(ae
->getValue());
1232 markAllLocalExprAltered(ae
->getVariable());
1234 int interf
= findInterf(ae
->getVariable(), false, rep
);
1235 if (interf
== SameAccess
) {
1236 switch (rep
->getKindOf()) {
1237 case Expression::KindOfAssignmentExpression
: {
1238 AssignmentExpressionPtr a
= spc(AssignmentExpression
, rep
);
1239 rep
= a
->getVariable();
1240 if (Option::EliminateDeadCode
) {
1241 ExpressionPtr value
= a
->getValue();
1242 if (value
->getContext() & Expression::RefValue
) {
1245 if (!Expression::CheckNeeded(a
->getVariable(), value
) ||
1246 m_accessList
.isSubLast(a
) ||
1247 (value
->isTemporary() && m_expr
->hasSubExpr(a
))) {
1248 a
->setReplacement(value
);
1254 case Expression::KindOfBinaryOpExpression
: {
1255 BinaryOpExpressionPtr b
= spc(BinaryOpExpression
, rep
);
1256 if (Option::EliminateDeadCode
) {
1257 bool ok
= b
->getActualType() &&
1258 b
->getActualType()->isNoObjectInvolved();
1260 switch (b
->getOp()) {
1267 case T_CONCAT_EQUAL
:
1279 ExpressionPtr rhs
= b
->getExp2()->clone();
1280 ExpressionPtr lhs
= b
->getExp1()->clone();
1281 lhs
->clearContext();
1284 ExpressionPtr(new BinaryOpExpression(
1285 b
->getScope(), b
->getLocation(),
1286 lhs
, rhs
, getOpForAssignmentOp(b
->getOp()))));
1293 case Expression::KindOfUnaryOpExpression
: {
1294 UnaryOpExpressionPtr u
= spc(UnaryOpExpression
, rep
);
1295 assert(u
->getOp() == T_INC
|| u
->getOp() == T_DEC
);
1296 if (Option::EliminateDeadCode
) {
1297 if (u
->getActualType() && u
->getActualType()->isInteger()) {
1298 ExpressionPtr val
= u
->getExpression()->clone();
1299 val
->clearContext();
1300 if (u
->getFront()) {
1302 (new ScalarExpression(u
->getScope(), u
->getLocation(),
1303 T_LNUMBER
, string("1")));
1305 val
= ExpressionPtr(
1306 new BinaryOpExpression(u
->getScope(), u
->getLocation(),
1308 u
->getOp() == T_INC
? '+' : '-'));
1312 u
->setReplacement(val
);
1315 rep
= u
->getExpression();
1322 always_assert(rep
->getKindOf() == ae
->getVariable()->getKindOf());
1323 ae
->getVariable()->setCanonID(rep
->getCanonID());
1325 ae
->getVariable()->setCanonID(m_nextID
++);
1327 add(m_accessList
, e
);
1331 case Expression::KindOfArrayElementExpression
:
1332 case Expression::KindOfObjectPropertyExpression
:
1333 if (!e
->hasContext(Expression::AccessContext
)) {
1334 processAccessChain(e
);
1336 case Expression::KindOfSimpleVariable
:
1337 case Expression::KindOfDynamicVariable
:
1338 case Expression::KindOfStaticMemberExpression
:
1339 if (e
->hasContext(Expression::UnsetContext
) &&
1340 e
->hasContext(Expression::LValue
)) {
1341 markAllLocalExprAltered(e
);
1342 if (Option::EliminateDeadCode
) {
1344 int interf
= findInterf(e
, false, rep
);
1345 if (interf
== SameAccess
) {
1346 if (rep
->getKindOf() == e
->getKindOf()) {
1347 // if we hit a previous unset of the same thing
1348 // we can delete this one
1349 if (rep
->hasContext(Expression::UnsetContext
) &&
1350 rep
->hasContext(Expression::LValue
)) {
1351 return canonicalizeRecurNonNull(e
->makeConstant(m_arp
, "null"));
1354 switch (rep
->getKindOf()) {
1355 case Expression::KindOfAssignmentExpression
:
1358 Handling unset of a variable which hasnt been
1359 used since it was last assigned
1361 if (!e
->is(Expression::KindOfSimpleVariable
)) {
1365 AssignmentExpressionPtr a
= spc(AssignmentExpression
, rep
);
1368 a
->getVariable()->is(Expression::KindOfSimpleVariable
));
1369 SimpleVariablePtr variable
=
1370 spc(SimpleVariable
, a
->getVariable());
1371 if (variable
->couldBeAliased()) {
1375 ExpressionPtr value
= a
->getValue();
1376 if (value
->getContext() & Expression::RefValue
) {
1379 if (!Expression::CheckNeeded(a
->getVariable(), value
) ||
1380 m_accessList
.isSubLast(a
) ||
1381 (value
->isTemporary() && m_expr
->hasSubExpr(a
))) {
1382 rep
->setReplacement(value
);
1385 ExpressionPtr last
= value
;
1386 while (last
->is(Expression::KindOfAssignmentExpression
)) {
1387 last
= spc(AssignmentExpression
, last
)->getValue();
1389 if (!last
->isScalar()) {
1390 ExpressionPtr cur
= value
;
1392 ExpressionPtr rhs
= cur
;
1394 if (cur
->is(Expression::KindOfAssignmentExpression
)) {
1395 rhs
= spc(AssignmentExpression
, cur
)->getVariable();
1396 next
= spc(AssignmentExpression
, cur
)->getValue();
1400 if (!rhs
->hasEffect()) {
1402 ExpressionPtr v
= rhs
->clone();
1404 v
= canonicalizeRecurNonNull(v
);
1406 while (v
->getCanonPtr() && v
->getCanonPtr() != last
) {
1407 v
= v
->getCanonPtr();
1409 if (v
->getCanonPtr()) {
1410 if (a
->isUnused() && rhs
== value
) {
1411 value
= value
->replaceValue(
1412 canonicalizeRecurNonNull(
1413 value
->makeConstant(m_arp
, "null")));
1415 a
->recomputeEffects();
1418 ExpressionListPtr
el(
1420 a
->getScope(), a
->getLocation(),
1421 ExpressionList::ListKindWrapped
));
1422 a
= spc(AssignmentExpression
, a
->clone());
1424 el
->addElement(a
->getValue());
1425 a
->setValue(value
->makeConstant(m_arp
, "null"));
1426 rep
->setReplacement(el
);
1443 add(m_accessList
, e
);
1447 case Expression::KindOfConstantExpression
: {
1449 Expressions with AccessContext need to be taken care of
1450 by processAccessChain(), which adds the entire access chain
1451 to the access list after all its side effects have taken place.
1452 In the case of assignment, or binary op assignment, its added
1453 after the rhs has been fully processed too.
1455 bool doArrayCSE
= Option::ArrayAccessIdempotent
&& m_postOpt
;
1456 if (e
->hasContext(Expression::AccessContext
)) {
1457 always_assert(doAccessChains
);
1458 if (e
->getContext() & (Expression::LValue
|
1459 Expression::RefValue
|
1460 Expression::RefParameter
|
1461 Expression::DeepReference
|
1462 Expression::UnsetContext
)) {
1465 findInterf(e
, true, rep
, nullptr, doArrayCSE
);
1466 add(m_accessList
, e
);
1467 if (interf
== SameAccess
) {
1468 if (e
->getKindOf() == rep
->getKindOf()) {
1469 // e->setCanonID(rep->getCanonID());
1470 } else if (rep
->is(Expression::KindOfBinaryOpExpression
) ||
1471 rep
->is(Expression::KindOfUnaryOpExpression
)) {
1473 } else if (rep
->is(Expression::KindOfAssignmentExpression
)) {
1475 // spc(AssignmentExpression, rep)->getVariable()->getCanonID());
1477 rep
= spc(AssignmentExpression
, rep
)->getValue();
1478 } while (rep
->is(Expression::KindOfAssignmentExpression
));
1480 e
->setCanonPtr(rep
);
1481 } else if (interf
== SameLValueAccess
) {
1482 setCanonPtrForArrayCSE(e
, rep
);
1483 } else if (interf
== InterfAccess
&& rep
&&
1484 rep
->is(Expression::KindOfAssignmentExpression
) &&
1485 (e
->is(Expression::KindOfSimpleVariable
) ||
1486 e
->is(Expression::KindOfArrayElementExpression
))) {
1487 ExpressionPtr val
= rep
;
1489 val
= spc(AssignmentExpression
, val
)->getValue();
1490 } while (val
->is(Expression::KindOfAssignmentExpression
));
1491 if (!val
->isScalar()) break;
1492 ExpressionPtr var
= spc(AssignmentExpression
, rep
)->getVariable();
1493 while (var
->is(Expression::KindOfArrayElementExpression
)) {
1494 var
= spc(ArrayElementExpression
, var
)->getVariable();
1495 if (var
->getKindOf() == e
->getKindOf()) {
1496 if (var
->is(Expression::KindOfSimpleVariable
)) {
1497 if (canonCompare(var
, e
)) {
1498 e
->setCanonPtr(var
);
1502 ArrayElementExpressionPtr
a1(
1503 spc(ArrayElementExpression
, e
));
1504 ArrayElementExpressionPtr
a2(
1505 spc(ArrayElementExpression
, var
));
1506 if (compareArrays(a1
, a2
)) {
1507 e
->setCanonPtr(var
);
1518 if (!(e
->getContext() & (Expression::LValue
|
1519 Expression::RefValue
|
1520 Expression::RefParameter
|
1521 Expression::DeepReference
|
1522 Expression::UnsetContext
))) {
1525 findInterf(e
, true, rep
, nullptr, doArrayCSE
);
1526 if (!m_inPseudoMain
&& interf
== DisjointAccess
&& !m_cleared
&&
1527 e
->is(Expression::KindOfSimpleVariable
) &&
1529 Symbol
*s
= spc(SimpleVariable
, e
)->getSymbol();
1530 if (s
&& !s
->isParameter() && !s
->isGeneratorParameter() &&
1531 !s
->isClosureVar()) {
1532 rep
= e
->makeConstant(m_arp
, "null");
1533 Compiler::Error(Compiler::UseUndeclaredVariable
, e
);
1534 if (m_variables
->getAttribute(VariableTable::ContainsCompact
)) {
1535 rep
= ExpressionPtr(
1536 new UnaryOpExpression(e
->getScope(), e
->getLocation(),
1537 rep
, T_UNSET_CAST
, true));
1539 return e
->replaceValue(canonicalizeRecurNonNull(rep
));
1542 if (interf
== SameAccess
) {
1543 if (rep
->getKindOf() == e
->getKindOf()) {
1544 if (rep
->hasContext(Expression::UnsetContext
) &&
1545 rep
->hasContext(Expression::LValue
) &&
1546 !rep
->is(Expression::KindOfConstantExpression
)) {
1547 return e
->replaceValue(
1548 canonicalizeRecurNonNull(e
->makeConstant(m_arp
, "null")));
1550 add(m_accessList
, e
);
1551 e
->setCanonID(rep
->getCanonID());
1552 e
->setCanonPtr(rep
);
1553 if (doArrayCSE
) setCanonPtrForArrayCSE(e
, rep
);
1554 return ExpressionPtr();
1556 if (Option::LocalCopyProp
&&
1557 rep
->getKindOf() == Expression::KindOfAssignmentExpression
) {
1558 AssignmentExpressionPtr ae
= spc(AssignmentExpression
,rep
);
1559 ExpressionPtr cur
= ae
->getValue(), last
= cur
;
1560 while (last
->is(Expression::KindOfAssignmentExpression
)) {
1561 last
= spc(AssignmentExpression
, last
)->getValue();
1563 if (last
->isScalar()) {
1564 last
= last
->clone();
1569 ExpressionPtr rhs
= cur
;
1571 if (cur
->is(Expression::KindOfAssignmentExpression
)) {
1572 rhs
= spc(AssignmentExpression
, cur
)->getVariable();
1573 next
= spc(AssignmentExpression
, cur
)->getValue();
1577 if (rhs
->is(Expression::KindOfSimpleVariable
)) {
1579 rhs
->clearContext();
1581 int i
= findInterf(rhs
, true, orig
);
1582 if (i
== SameAccess
&&
1583 (sameExpr(cur
, orig
) || (next
&& sameExpr(next
, orig
)))) {
1584 e
->recomputeEffects();
1585 return e
->replaceValue(canonicalizeRecurNonNull(rhs
));
1591 !last
->is(Expression::KindOfYieldExpression
) &&
1592 ae
->isUnused() && m_accessList
.isLast(ae
) &&
1593 !e
->hasAnyContext(Expression::AccessContext
|
1594 Expression::ObjectContext
|
1595 Expression::ExistContext
|
1596 Expression::UnsetContext
)) {
1598 ae
->setContext(Expression::DeadStore
);
1599 ae
->setValue(ae
->makeConstant(m_arp
, "null"));
1600 ae
->setVariable(ae
->makeConstant(m_arp
, "null"));
1601 e
->recomputeEffects();
1603 return e
->replaceValue(canonicalizeRecurNonNull(rep
));
1605 e
->setCanonPtr(last
);
1607 } else if (interf
== SameLValueAccess
) {
1608 setCanonPtrForArrayCSE(e
, rep
);
1611 add(m_accessList
, e
);
1615 case Expression::KindOfBinaryOpExpression
: {
1616 BinaryOpExpressionPtr bop
= spc(BinaryOpExpression
, e
);
1617 int rop
= getOpForAssignmentOp(bop
->getOp());
1618 if (bop
->hasContext(Expression::DeadStore
)) {
1620 ExpressionPtr rhs
= bop
->getExp2();
1621 ExpressionPtr lhs
= bop
->getExp1();
1622 lhs
->clearContext();
1623 e
->recomputeEffects();
1624 return bop
->replaceValue(
1625 canonicalizeNonNull(ExpressionPtr(
1626 new BinaryOpExpression(
1627 bop
->getScope(), bop
->getLocation(),
1631 markAllLocalExprAltered(bop
);
1632 ExpressionPtr lhs
= bop
->getExp1();
1635 int interf
= findInterf(lhs
, true, alt
, &flags
);
1636 if (interf
== SameAccess
&& !(flags
& NoCopyProp
)) {
1637 switch (alt
->getKindOf()) {
1638 case Expression::KindOfAssignmentExpression
: {
1639 ExpressionPtr op0
= spc(AssignmentExpression
,alt
)->getValue();
1640 if (op0
->isScalar()) {
1641 ExpressionPtr op1
= bop
->getExp2();
1643 (new BinaryOpExpression(e
->getScope(), e
->getLocation(),
1644 op0
->clone(), op1
->clone(), rop
)));
1647 lhs
->clearContext(Expression::OprLValue
);
1648 return e
->replaceValue(
1649 canonicalizeRecurNonNull(
1650 ExpressionPtr(new AssignmentExpression(
1651 e
->getScope(), e
->getLocation(),
1652 lhs
, rhs
, false))));
1654 alt
= spc(AssignmentExpression
,alt
)->getVariable();
1657 case Expression::KindOfBinaryOpExpression
: {
1658 BinaryOpExpressionPtr
b2(spc(BinaryOpExpression
, alt
));
1659 if (!(flags
& NoDeadStore
) && b2
->getOp() == bop
->getOp()) {
1676 ExpressionPtr op0
= b2
->getExp2();
1677 bool ok
= op0
->isScalar();
1678 if (!ok
&& !op0
->hasEffect()) {
1680 ExpressionPtr v
= op0
->clone();
1682 v
= canonicalizeRecurNonNull(v
);
1684 while (v
->getCanonPtr() && v
->getCanonPtr() != op0
) {
1685 v
= v
->getCanonPtr();
1687 ok
= (v
->getCanonPtr() != nullptr);
1690 b2
->setContext(Expression::DeadStore
);
1691 ExpressionPtr
r(new BinaryOpExpression(
1692 bop
->getScope(), bop
->getLocation(),
1693 op0
->clone(), bop
->getExp2(),
1695 ExpressionPtr
b(new BinaryOpExpression(
1696 bop
->getScope(), bop
->getLocation(),
1697 lhs
, r
, bop
->getOp()));
1698 return e
->replaceValue(canonicalizeRecurNonNull(b
));
1702 alt
= spc(BinaryOpExpression
,alt
)->getExp1();
1705 case Expression::KindOfUnaryOpExpression
:
1706 alt
= spc(UnaryOpExpression
,alt
)->getExpression();
1711 always_assert(alt
->getKindOf() == lhs
->getKindOf());
1712 lhs
->setCanonID(alt
->getCanonID());
1714 lhs
->setCanonID(m_nextID
++);
1716 add(m_accessList
, e
);
1723 case Expression::KindOfUnaryOpExpression
: {
1724 UnaryOpExpressionPtr uop
= spc(UnaryOpExpression
, e
);
1725 switch (uop
->getOp()) {
1729 markAllLocalExprAltered(e
);
1731 int interf
= findInterf(uop
->getExpression(), true, alt
);
1732 if (interf
== SameAccess
) {
1733 switch (alt
->getKindOf()) {
1734 case Expression::KindOfAssignmentExpression
:
1735 case Expression::KindOfBinaryOpExpression
:
1736 case Expression::KindOfUnaryOpExpression
:
1737 alt
= alt
->getStoreVariable();
1742 always_assert(alt
->getKindOf() ==
1743 uop
->getExpression()->getKindOf());
1744 uop
->getExpression()->setCanonID(alt
->getCanonID());
1746 uop
->getExpression()->setCanonID(m_nextID
++);
1749 add(m_accessList
, e
);
1752 if (uop
->getLocalEffects() == Expression::UnknownEffect
) {
1753 add(m_accessList
, e
);
1762 case Expression::KindOfExpressionList
:
1763 if (e
->hasContext(Expression::UnsetContext
) &&
1764 spc(ExpressionList
, e
)->getListKind() ==
1765 ExpressionList::ListKindParam
) {
1766 ExpressionListPtr el
= spc(ExpressionList
, e
);
1767 for (int i
= el
->getCount(); i
--; ) {
1768 if ((*el
)[i
]->isScalar()) {
1769 el
->removeElement(i
);
1779 return ExpressionPtr();
1782 void AliasManager::canonicalizeKid(ConstructPtr c
, ExpressionPtr kid
, int i
) {
1783 assert(c
->getNthKid(i
) == kid
);
1786 StatementPtr
sp(dpc(Statement
, c
));
1787 if (sp
) beginInExpression(sp
, kid
);
1788 kid
= canonicalizeRecur(kid
);
1790 c
->setNthKid(i
, kid
);
1791 c
->recomputeEffects();
1795 endInExpression(sp
);
1796 ExpressionPtr
kid0(dpc(Expression
, c
->getNthKid(i
)));
1798 kid0
->computeLocalExprAltered();
1803 int AliasManager::canonicalizeKid(ConstructPtr c
, ConstructPtr kid
, int i
) {
1804 assert(c
->getNthKid(i
) == kid
);
1806 int ret
= FallThrough
;
1808 ExpressionPtr e
= dpc(Expression
, kid
);
1810 canonicalizeKid(c
, e
, i
);
1812 StatementPtr s
= dpc(Statement
, kid
);
1813 s
= canonicalizeRecur(s
, ret
);
1816 c
->recomputeEffects();
1824 ExpressionPtr
AliasManager::canonicalizeRecur(ExpressionPtr e
) {
1825 if (e
->isVisited()) return ExpressionPtr();
1826 if (ExpressionPtr rep
= e
->fetchReplacement()) {
1827 if (e
->getContainedEffects() != rep
->getContainedEffects()) {
1828 e
->recomputeEffects();
1830 return canonicalizeRecurNonNull(e
->replaceValue(rep
));
1833 bool delayVars
= true;
1834 bool pushStack
= false;
1835 bool inCall
= false;
1836 bool setInCall
= true;
1838 switch (e
->getKindOf()) {
1839 case Expression::KindOfQOpExpression
: {
1840 QOpExpressionPtr
qe(spc(QOpExpression
, e
));
1841 canonicalizeKid(e
, qe
->getCondition(), 0);
1843 if (ExpressionPtr e1
= qe
->getYes()) {
1844 canonicalizeKid(e
, e1
, 1);
1847 canonicalizeKid(e
, qe
->getNo(), 2);
1849 return canonicalizeNode(e
);
1851 case Expression::KindOfBinaryOpExpression
: {
1852 BinaryOpExpressionPtr
binop(spc(BinaryOpExpression
, e
));
1853 if (binop
->isShortCircuitOperator()) {
1854 canonicalizeKid(e
, binop
->getExp1(), 0);
1856 canonicalizeKid(e
, binop
->getExp2(), 1);
1858 return canonicalizeNode(e
);
1862 case Expression::KindOfExpressionList
:
1866 case Expression::KindOfSimpleFunctionCall
:
1867 case Expression::KindOfNewObjectExpression
:
1868 case Expression::KindOfDynamicFunctionCall
:
1870 case Expression::KindOfObjectMethodExpression
:
1873 pushStack
= m_accessList
.size() > 0;
1880 ExpressionPtr aBack
;
1882 aBack
= m_accessList
.back();
1886 int n
= e
->getKidCount();
1887 if (n
< 2) delayVars
= false;
1888 if (e
->is(Expression::KindOfAssignmentExpression
)) delayVars
= false;
1891 for (int j
= delayVars
? 0 : 1; j
< 2; j
++) {
1892 for (int i
= 0; i
< n
; i
++) {
1893 if (ExpressionPtr kid
= e
->getNthExpr(i
)) {
1895 php doesnt evaluate simple variables at the point they are seen
1896 except in function parameters and function "addresses".
1899 the first $a is evaluated after the assignment. But in:
1901 the first $a is evaluated before the assignment.
1902 To deal with this, if we're not dealing with a parameter list, and
1903 there's more than one child node, we do two passes, and process the
1904 simple variables on the second pass.
1907 bool stash
= !kid
->is(Expression::KindOfSimpleVariable
) ||
1908 spc(SimpleVariable
, kid
)->getAlwaysStash();
1909 if (stash
== j
) continue;
1911 canonicalizeKid(e
, kid
, i
);
1916 if (pushStack
) m_exprBeginStack
.push_back(aBack
);
1917 ExpressionPtr
ret(canonicalizeNode(e
));
1918 if (pushStack
) m_exprBeginStack
.pop_back();
1923 StatementPtr
AliasManager::canonicalizeRecur(StatementPtr s
, int &ret
) {
1925 if (!s
|| s
->isVisited()) return StatementPtr();
1927 // Dont handle nested functions
1928 // they will be dealt with by another
1929 // top level call to optimize
1930 if (FunctionWalker::SkipRecurse(s
)) return StatementPtr();
1932 Statement::KindOf stype
= s
->getKindOf();
1934 int nkid
= s
->getKidCount();
1937 case Statement::KindOfUseTraitStatement
:
1938 case Statement::KindOfTraitPrecStatement
:
1939 case Statement::KindOfTraitAliasStatement
:
1940 return StatementPtr();
1941 case Statement::KindOfStaticStatement
:
1945 case Statement::KindOfClassVariable
:
1948 case Statement::KindOfClassConstant
:
1949 case Statement::KindOfGlobalStatement
:
1950 case Statement::KindOfUnsetStatement
:
1951 case Statement::KindOfExpStatement
:
1952 case Statement::KindOfStatementList
:
1953 case Statement::KindOfBlockStatement
:
1954 // No special action, just execute
1958 case Statement::KindOfIfStatement
: {
1959 IfStatementPtr is
= spc(IfStatement
, s
);
1960 StatementListPtr iflist
= is
->getIfBranches();
1962 for (int i
= 0, n
= iflist
->getKidCount(); i
< n
; i
++) {
1963 IfBranchStatementPtr ifstmt
= spc(IfBranchStatement
, (*iflist
)[i
]);
1964 canonicalizeKid(ifstmt
, ifstmt
->getCondition(), 0);
1965 if (!i
) beginScope();
1967 canonicalizeKid(ifstmt
, ifstmt
->getStmt(), 1);
1969 if (i
+1 < n
) resetScope();
1978 case Statement::KindOfIfBranchStatement
:
1982 case Statement::KindOfForStatement
: {
1983 ForStatementPtr
fs(spc(ForStatement
, s
));
1984 canonicalizeKid(s
, fs
->getInitExp(), 0);
1986 canonicalizeKid(s
, fs
->getCondExp(), 1);
1987 canonicalizeKid(s
, fs
->getBody(), 2);
1989 canonicalizeKid(s
, fs
->getIncExp(), 3);
1994 case Statement::KindOfWhileStatement
:
1995 case Statement::KindOfDoStatement
:
1996 case Statement::KindOfForEachStatement
:
2001 case Statement::KindOfSwitchStatement
: {
2002 SwitchStatementPtr
ss(spc(SwitchStatement
, s
));
2003 canonicalizeKid(s
, ss
->getExp(), 0);
2009 case Statement::KindOfCaseStatement
:
2010 case Statement::KindOfLabelStatement
:
2014 case Statement::KindOfReturnStatement
: {
2015 ReturnStatementPtr
rs(spc(ReturnStatement
, s
));
2016 canonicalizeKid(s
, rs
->getRetExp(), 0);
2022 case Statement::KindOfBreakStatement
:
2023 case Statement::KindOfContinueStatement
:
2024 case Statement::KindOfGotoStatement
:
2028 case Statement::KindOfTryStatement
: {
2029 TryStatementPtr
trs(spc(TryStatement
, s
));
2031 canonicalizeKid(s
, trs
->getBody(), 0);
2034 canonicalizeKid(s
, trs
->getCatches(), 1);
2035 if (trs
->getFinally()) {
2037 canonicalizeKid(s
, trs
->getFinally(), 2);
2044 case Statement::KindOfFinallyStatement
: {
2048 case Statement::KindOfTypedefStatement
:
2051 case Statement::KindOfCatchStatement
:
2056 case Statement::KindOfThrowStatement
:
2060 case Statement::KindOfEchoStatement
:
2062 EchoStatementPtr
es(spc(EchoStatement
, s
));
2063 ExpressionListPtr exprs
= es
->getExpressionList();
2064 for (int i
= 0; i
< exprs
->getCount(); i
++) {
2065 ExpressionPtr
kid(exprs
->getNthExpr(i
));
2066 beginInExpression(es
, kid
);
2067 canonicalizeKid(exprs
, kid
, i
);
2068 endInExpression(es
);
2069 kid
->computeLocalExprAltered();
2070 ExpressionPtr
e(new ScalarExpression(BlockScopePtr(), LocationPtr(),
2071 T_STRING
, string("io")));
2072 add(m_accessList
, e
);
2083 for (int i
= start
; i
< nkid
; i
++) {
2084 ConstructPtr cp
= s
->getNthKid(i
);
2088 int action
= canonicalizeKid(s
, cp
, i
);
2104 if (m_preOpt
) rep
= s
->preOptimize(m_arp
);
2105 if (m_postOpt
) rep
= s
->postOptimize(m_arp
);
2107 s
= canonicalizeRecur(rep
, ret
);
2110 return StatementPtr();
2113 int AliasManager::collectAliasInfoRecur(ConstructPtr cs
, bool unused
) {
2119 cs
->clearChildOfYield();
2121 StatementPtr s
= dpc(Statement
, cs
);
2123 switch (s
->getKindOf()) {
2124 case Statement::KindOfFunctionStatement
:
2125 case Statement::KindOfMethodStatement
:
2126 case Statement::KindOfClassStatement
:
2127 case Statement::KindOfInterfaceStatement
:
2128 m_inlineAsExpr
= false;
2135 int nkid
= cs
->getKidCount();
2137 for (int i
= 0; i
< nkid
; i
++) {
2138 ConstructPtr kid
= cs
->getNthKid(i
);
2140 kidCost
+= collectAliasInfoRecur(kid
, cs
->kidUnused(i
));
2145 bool inlineOk
= false;
2146 Statement::KindOf skind
= s
->getKindOf();
2148 case Statement::KindOfGlobalStatement
:
2149 case Statement::KindOfStaticStatement
:
2151 ExpressionListPtr vars
= (skind
== Statement::KindOfGlobalStatement
)
2152 ? spc(GlobalStatement
, s
)->getVars()
2153 : spc(StaticStatement
, s
)->getVars();
2155 for (int i
= 0, n
= vars
->getCount(); i
< n
; i
++) {
2156 ExpressionPtr e
= (*vars
)[i
];
2157 if (AssignmentExpressionPtr ae
= dpc(AssignmentExpression
, e
)) {
2158 e
= ae
->getVariable();
2160 if (SimpleVariablePtr sv
= dpc(SimpleVariable
, e
)) {
2161 if (Symbol
*sym
= sv
->getSymbol()) {
2162 sym
->setReferenced();
2164 if (skind
== Statement::KindOfGlobalStatement
) {
2166 } else if (!m_variables
->isPseudoMainTable()) {
2167 m_variables
->addStaticVariable(sym
, m_arp
);
2174 case Statement::KindOfExpStatement
:
2175 case Statement::KindOfStatementList
:
2178 case Statement::KindOfCatchStatement
:
2180 CatchStatementPtr
c(spc(CatchStatement
, s
));
2181 if (c
->getVariable()->isThis()) {
2182 // Since catching $this results in re-assignment to $this, forcing
2183 // a variable table is the easiest way to force v_this to exist as
2184 // a local variable in the current scope. While this is clearly
2185 // not optimal, I don't believe there is a compelling reason to
2186 // optimize for this case.
2187 m_variables
->setAttribute(VariableTable::ContainsLDynamicVariable
);
2191 case Statement::KindOfReturnStatement
:
2193 if (m_nrvoFix
>= 0) {
2194 ExpressionPtr e
= spc(ReturnStatement
, s
)->getRetExp();
2195 if (!e
|| !e
->is(Expression::KindOfSimpleVariable
)) {
2198 SimpleVariablePtr sv
= spc(SimpleVariable
, e
);
2199 const std::string
&n
= sv
->getName();
2203 } else if (m_returnVar
!= n
) {
2209 case Statement::KindOfForEachStatement
: {
2210 ForEachStatementPtr
fs(static_pointer_cast
<ForEachStatement
>(s
));
2211 SimpleVariablePtr name
= dpc(SimpleVariable
, fs
->getNameExp());
2213 if (Symbol
*sym
= name
->getSymbol()) {
2217 SimpleVariablePtr value
= dpc(SimpleVariable
, fs
->getValueExp());
2219 if (Symbol
*sym
= value
->getSymbol()) {
2229 m_inlineAsExpr
= false;
2232 ExpressionPtr e
= spc(Expression
, cs
);
2233 if (e
->isNoRemove()) m_hasTypeAssertions
= true;
2234 if (e
->getContext() & Expression::DeadStore
) m_hasDeadStore
= true;
2238 if (e
->is(Expression::KindOfSimpleVariable
)) {
2240 Symbol
*sym
= spc(SimpleVariable
, e
)->getSymbol();
2241 if (!sym
|| !sym
->isParameter()) kidCost
= 1;
2243 } else if (!e
->isScalar()) {
2246 } else if (e
->getLocalEffects() & ~Expression::AccessorEffect
) {
2249 } else if (!e
->is(Expression::KindOfExpressionList
)) {
2252 e
->setUnused(unused
);
2253 int context
= e
->getContext();
2254 int ekind
= e
->getKindOf();
2256 case Expression::KindOfAssignmentExpression
:
2258 AssignmentExpressionPtr ae
= spc(AssignmentExpression
, e
);
2259 ExpressionPtr var
= ae
->getVariable();
2260 ExpressionPtr val
= ae
->getValue();
2261 if (var
->is(Expression::KindOfSimpleVariable
)) {
2262 if (val
->getContext() & Expression::RefValue
) {
2263 if (Symbol
*sym
= spc(SimpleVariable
, var
)->getSymbol()) {
2264 sym
->setReferenced();
2269 Expression::CheckNeeded(var
, val
);
2274 case Expression::KindOfListAssignment
:
2276 ListAssignmentPtr la
= spc(ListAssignment
, e
);
2277 ExpressionListPtr vars
= la
->getVariables();
2278 for (int i
= vars
->getCount(); i
--; ) {
2279 ExpressionPtr v
= (*vars
)[i
];
2280 if (v
&& v
->is(Expression::KindOfSimpleVariable
)) {
2281 SimpleVariablePtr sv
= spc(SimpleVariable
, v
);
2282 if (Symbol
*sym
= spc(SimpleVariable
, v
)->getSymbol()) {
2289 case Expression::KindOfSimpleVariable
:
2291 SimpleVariablePtr
sv(spc(SimpleVariable
, e
));
2292 if (Symbol
*sym
= sv
->getSymbol()) {
2293 bool ref
= (context
& (Expression::RefValue
|
2294 Expression::RefAssignmentLHS
)) ||
2295 sym
->isRefClosureVar();
2297 sym
->setReferenced();
2299 bool unset
= ((context
& Expression::UnsetContext
) &&
2300 (context
& Expression::LValue
));
2302 sv
->getFunctionScope()->setContainsThis();
2303 if (!e
->hasContext(Expression::ObjectContext
)) {
2304 sv
->getFunctionScope()->setContainsBareThis(true, ref
|| unset
);
2305 } else if (m_graph
) {
2306 int &id
= m_gidMap
["v:this"];
2307 if (!id
) id
= m_gidMap
.size();
2310 } else if (m_graph
) {
2311 m_objMap
[sym
->getName()] = sv
;
2316 if (!(context
& (Expression::AssignmentLHS
|
2317 Expression::UnsetContext
))) {
2323 case Expression::KindOfDynamicVariable
:
2324 m_variables
->setAttribute(VariableTable::ContainsDynamicVariable
);
2325 if (context
& (Expression::RefValue
|
2326 Expression::LValue
)) {
2327 m_variables
->setAttribute(VariableTable::ContainsLDynamicVariable
);
2328 if (context
& Expression::RefValue
) {
2333 case Expression::KindOfIncludeExpression
:
2335 IncludeExpressionPtr
inc(spc(IncludeExpression
, e
));
2336 m_variables
->setAttribute(VariableTable::ContainsLDynamicVariable
);
2339 case Expression::KindOfArrayElementExpression
:
2343 e
->is(Expression::KindOfArrayElementExpression
)) {
2344 e
= spc(ArrayElementExpression
, e
)->getVariable();
2346 if (e
->is(Expression::KindOfSimpleVariable
)) {
2347 if (Symbol
*sym
= spc(SimpleVariable
, e
)->getSymbol()) {
2348 if (context
& Expression::RefValue
) {
2349 sym
->setReferenced();
2351 sym
->setUsed(); // need this for UnsetContext
2356 case Expression::KindOfObjectPropertyExpression
:
2358 ExpressionPtr obj
= spc(ObjectPropertyExpression
, e
)->getObject();
2359 if (obj
->is(Expression::KindOfSimpleVariable
)) {
2360 if (Symbol
*sym
= spc(SimpleVariable
, obj
)->getSymbol()) {
2361 if (context
& Expression::RefValue
) {
2362 sym
->setReferenced();
2364 sym
->setUsed(); // need this for UnsetContext
2369 case Expression::KindOfSimpleFunctionCall
:
2371 SimpleFunctionCallPtr
sfc(spc(SimpleFunctionCall
, e
));
2372 if (sfc
->getName() == "hphp_create_continuation") {
2373 m_inlineAsExpr
= false;
2375 sfc
->updateVtFlags();
2377 case Expression::KindOfDynamicFunctionCall
:
2378 case Expression::KindOfClassConstantExpression
:
2379 case Expression::KindOfStaticMemberExpression
:
2380 case Expression::KindOfNewObjectExpression
: {
2381 StaticClassName
*p
= dynamic_cast<StaticClassName
*>(e
.get());
2383 bool useLSB
= false;
2384 if (p
->isStatic()) {
2386 } else if (ekind
== Expression::KindOfDynamicFunctionCall
) {
2387 if ((p
->getClassName().empty() && !p
->getClass()) ||
2388 p
->isParent() || p
->isSelf()) {
2393 m_scope
->getContainingFunction()->setNextLSB(true);
2396 const std::string
&name
= p
->getClassName();
2397 if (!name
.empty()) {
2398 int &id
= m_gidMap
[name
];
2399 if (!id
) id
= m_gidMap
.size();
2405 case Expression::KindOfClosureExpression
:
2406 // currently disable inlining for scopes with closure
2407 // expressions. TODO: revisit this later
2408 m_inlineAsExpr
= false;
2410 case Expression::KindOfYieldExpression
:
2411 spc(YieldExpression
, e
)->getValueExpression()->setChildOfYield();
2413 case Expression::KindOfUnaryOpExpression
:
2414 if (Option::EnableEval
> Option::NoEval
&& spc(UnaryOpExpression
, e
)->
2415 getOp() == T_EVAL
) {
2416 m_variables
->setAttribute(VariableTable::ContainsLDynamicVariable
);
2420 case Expression::KindOfBinaryOpExpression
: {
2421 BinaryOpExpressionPtr
b(spc(BinaryOpExpression
, e
));
2422 if (b
->getOp() == T_INSTANCEOF
) {
2423 ExpressionPtr s
= b
->getExp2();
2424 if (s
->is(Expression::KindOfScalarExpression
)) {
2425 ScalarExpressionPtr
scalar(spc(ScalarExpression
, s
));
2426 if (!scalar
->isQuoted() && scalar
->getString() == "static") {
2427 m_scope
->getContainingFunction()->setNextLSB(true);
2430 } else if (unused
&& b
->isShortCircuitOperator()) {
2431 b
->getExp2()->setUnused(true);
2435 case Expression::KindOfQOpExpression
: {
2436 QOpExpressionPtr
q(spc(QOpExpression
, e
));
2438 if (ExpressionPtr t1
= q
->getYes()) t1
->setUnused(true);
2439 q
->getNo()->setUnused(true);
2450 void AliasManager::gatherInfo(AnalysisResultConstPtr ar
, MethodStatementPtr m
) {
2452 FunctionScopeRawPtr func
= m
->getFunctionScope();
2454 m_variables
= func
->getVariables();
2455 m_variables
->clearUsed();
2456 m_inPseudoMain
= func
->inPseudoMain();
2458 if (ExpressionListPtr pPtr
= m
->getParams()) {
2459 ExpressionList
¶ms
= *pPtr
;
2460 for (int i
= params
.getCount(); i
--; ) {
2461 ParameterExpressionPtr p
= spc(ParameterExpression
, params
[i
]);
2462 if (Symbol
*sym
= m_variables
->getSymbol(p
->getName())) {
2463 if (sym
->isCallTimeRef() || p
->isRef()) {
2464 sym
->setReferenced();
2469 if (ExpressionListPtr useVars
= func
->getClosureVars()) {
2470 for (int i
= 0; i
< useVars
->getCount(); i
++) {
2471 ParameterExpressionPtr p
= dpc(ParameterExpression
, (*useVars
)[i
]);
2473 if (Symbol
*sym
= m_variables
->getSymbol(p
->getName())) {
2475 sym
->setReferenced();
2482 if (!m_inPseudoMain
) {
2483 m_variables
->clearAttribute(VariableTable::ContainsLDynamicVariable
);
2484 m_variables
->clearAttribute(VariableTable::ContainsDynamicVariable
);
2485 m_variables
->clearAttribute(VariableTable::ContainsCompact
);
2486 m_variables
->clearAttribute(VariableTable::ContainsExtract
);
2489 func
->setContainsThis(false);
2490 func
->setContainsBareThis(false);
2491 func
->setInlineSameContext(false);
2492 func
->setNextLSB(false);
2494 int i
, nkid
= m
->getKidCount(), cost
= 0;
2495 for (i
= 0; i
< nkid
; i
++) {
2496 ConstructPtr
cp(m
->getNthKid(i
));
2497 int c
= collectAliasInfoRecur(cp
, false);
2498 if (cp
== m
->getStmts()) cost
= c
;
2501 if (m_inlineAsExpr
) {
2502 if (cost
> Option::AutoInline
||
2503 func
->isVariableArgument() ||
2504 m_variables
->getAttribute(VariableTable::ContainsDynamicVariable
) ||
2505 m_variables
->getAttribute(VariableTable::ContainsExtract
) ||
2506 m_variables
->getAttribute(VariableTable::ContainsCompact
) ||
2507 m_variables
->getAttribute(VariableTable::ContainsGetDefinedVars
)) {
2508 m_inlineAsExpr
= false;
2511 func
->setInlineAsExpr(m_inlineAsExpr
);
2513 if (!func
->nextLSB()) {
2514 if (func
->usesLSB()) {
2515 func
->clearUsesLSB();
2519 func
->setInlineSameContext(true);
2523 static void markAvailable(ExpressionRawPtr e
) {
2524 if (e
->is(Expression::KindOfSimpleVariable
)) {
2525 SimpleVariableRawPtr
sv(spc(SimpleVariable
,e
));
2529 StaticClassName
*scn
= dynamic_cast<StaticClassName
*>(e
.get());
2535 class TypeAssertionInserter
{
2537 explicit TypeAssertionInserter(AnalysisResultConstPtr ar
) :
2538 m_ar(ar
), m_changed(false) {
2539 BuildAssertionMap();
2541 bool walk(StatementPtr stmt
) {
2543 createTypeAssertions(stmt
);
2548 #define CONSTRUCT_PARAMS(from) \
2549 (from)->getScope(), (from)->getLocation()
2551 AnalysisResultConstPtr m_ar
;
2554 typedef std::pair
<int, TypePtr
> PosType
;
2555 typedef hphp_hash_map
<string
, PosType
, string_hash
>
2557 typedef hphp_hash_map
<string
, SimpleVariablePtr
, string_hash
>
2560 static StringPosTypeMap s_type_assertion_map
;
2561 static Mutex s_type_assertion_map_mutex
;
2563 static void BuildAssertionMap();
2565 ExpressionPtr
createTypeAssertionsForKids(ExpressionPtr parent
,
2570 for (int i
= startIdx
; i
< parent
->getKidCount(); i
++) {
2571 rep
= createTypeAssertions(parent
->getNthExpr(i
), passStmt
, negate
);
2576 void replaceExpression(
2577 ConstructPtr parent
, ExpressionPtr rep
, ExpressionPtr old
, int kid
) {
2579 assert(parent
->getKidCount() > kid
);
2580 assert(parent
->getNthKid(kid
) == old
);
2584 rep
->setActualType(old
->getActualType());
2585 rep
->setExpectedType(old
->getExpectedType());
2586 rep
->setImplementedType(old
->getImplementedType());
2587 old
->replaceValue(rep
);
2589 parent
->setNthKid(kid
, rep
);
2593 void replaceExpression(ExpressionPtr parent
, ExpressionPtr rep
, int kid
) {
2594 replaceExpression(parent
, rep
, parent
->getNthExpr(kid
), kid
);
2597 // returns the rep node for target, after the insertion
2598 ExpressionPtr
insertTypeAssertion(ExpressionPtr assertion
,
2599 ExpressionPtr target
) {
2602 assert(assertion
->is(Expression::KindOfSimpleVariable
) ||
2603 assertion
->is(Expression::KindOfExpressionList
));
2604 assert(assertion
->isNoRemove());
2606 if (ExpressionListPtr el
= dpc(ExpressionList
, target
)) {
2607 if (el
->getListKind() == ExpressionList::ListKindComma
) {
2608 assert(assertion
->is(Expression::KindOfSimpleVariable
));
2609 el
->insertElement(assertion
, el
->getCount() - 1);
2610 return ExpressionPtr();
2614 if (ExpressionListPtr el
= dpc(ExpressionList
, assertion
)) {
2615 ExpressionListPtr el0
= spc(ExpressionList
, el
->clone());
2616 el0
->insertElement(target
, el0
->getCount());
2620 ExpressionListPtr
el(
2622 CONSTRUCT_PARAMS(target
),
2623 ExpressionList::ListKindComma
));
2624 if (target
->isUnused()) {
2625 el
->setUnused(true);
2627 el
->addElement(assertion
);
2628 el
->addElement(target
);
2629 el
->setNoRemove(); // since it contains an assertion
2633 ExpressionPtr
newTypeAssertion(ExpressionPtr base
, TypePtr t
) {
2634 assert(base
->is(Expression::KindOfSimpleVariable
));
2635 ExpressionPtr
assertion(base
->clone());
2636 assertion
->setAssertedType(t
);
2637 assertion
->setNoRemove();
2641 ExpressionPtr
newInstanceOfAssertion(
2642 ExpressionPtr obj
, ExpressionPtr clsName
) {
2643 SimpleVariablePtr
sv(extractAssertableVariable(obj
));
2644 ScalarExpressionPtr
se(dpc(ScalarExpression
, clsName
));
2646 const string
&s
= se
->getLiteralString();
2647 if (s
.empty()) return ExpressionPtr();
2648 if (interface_supports_array(s
)) {
2649 // This could be an array, so don't assert anything
2650 return ExpressionPtr();
2652 TypePtr
o(Type::CreateObjectType(Util::toLower(s
)));
2654 // don't do specific type assertions for unknown classes
2655 ClassScopePtr
cscope(o
->getClass(m_ar
, sv
->getScope()));
2656 if (!cscope
) return newTypeAssertion(sv
, Type::Object
);
2658 // don't do type assertions for interfaces, since
2659 // user classes don't necessarily extend the interface class
2661 if (cscope
->isInterface()) {
2662 return newTypeAssertion(sv
, Type::Object
);
2665 // also don't do type assertions for derived by dynamic
2666 // classes, since these classes will be DynamicObjectData
2667 // instances at runtime (so we cannot emit a fast pointer cast
2669 if (cscope
->derivedByDynamic()) {
2670 return newTypeAssertion(sv
, Type::Object
);
2673 return newTypeAssertion(sv
, o
);
2675 return ExpressionPtr();
2678 SimpleVariablePtr
extractAssertableVariable(ExpressionPtr e
) {
2680 switch (e
->getKindOf()) {
2681 case Expression::KindOfSimpleVariable
:
2682 return spc(SimpleVariable
, e
);
2683 case Expression::KindOfAssignmentExpression
:
2685 AssignmentExpressionPtr
ae(spc(AssignmentExpression
, e
));
2686 return extractAssertableVariable(ae
->getVariable());
2691 return SimpleVariablePtr();
2694 ExpressionPtr
orAssertions(
2695 SimpleVariablePtr lhs
,
2696 SimpleVariablePtr rhs
) {
2697 assert(lhs
&& lhs
->isNoRemove() && lhs
->getAssertedType());
2698 assert(rhs
&& rhs
->isNoRemove() && rhs
->getAssertedType());
2699 assert(lhs
->getName() == rhs
->getName());
2701 Type::Union(m_ar
, lhs
->getAssertedType(), rhs
->getAssertedType()));
2702 ExpressionPtr
lhs0(lhs
->clone());
2703 lhs0
->setAssertedType(u
);
2707 ExpressionPtr
andAssertions(
2708 SimpleVariablePtr lhs
,
2709 SimpleVariablePtr rhs
) {
2710 assert(lhs
&& lhs
->isNoRemove() && lhs
->getAssertedType());
2711 assert(rhs
&& rhs
->isNoRemove() && rhs
->getAssertedType());
2712 assert(lhs
->getName() == rhs
->getName());
2715 m_ar
, lhs
->getAssertedType(), rhs
->getAssertedType()));
2716 ExpressionPtr
lhs0(lhs
->clone());
2717 lhs0
->setAssertedType(i
);
2721 ExpressionPtr
orAssertions(ExpressionPtr lhs
, ExpressionPtr rhs
) {
2722 if (!lhs
|| !rhs
) return ExpressionPtr();
2724 assert(lhs
->is(Expression::KindOfSimpleVariable
) ||
2725 lhs
->is(Expression::KindOfExpressionList
));
2726 assert(rhs
->is(Expression::KindOfSimpleVariable
) ||
2727 rhs
->is(Expression::KindOfExpressionList
));
2729 if (lhs
->is(Expression::KindOfSimpleVariable
) &&
2730 rhs
->is(Expression::KindOfSimpleVariable
) &&
2731 spc(SimpleVariable
, lhs
)->getName() ==
2732 spc(SimpleVariable
, rhs
)->getName()) {
2733 return orAssertions(
2734 spc(SimpleVariable
, lhs
),
2735 spc(SimpleVariable
, rhs
));
2738 return ExpressionPtr();
2741 bool isAllScalar(ExpressionListPtr ep
, int startIdx
) {
2742 assert(ep
&& ep
->getListKind() == ExpressionList::ListKindParam
);
2743 for (int i
= startIdx
; i
< ep
->getCount(); i
++) {
2744 ExpressionPtr
c((*ep
)[i
]);
2745 if (c
&& !c
->isScalar()) return false;
2750 ExpressionPtr
createTypeAssertions(ExpressionPtr from
,
2755 if (!from
) return ExpressionPtr();
2757 bool useKidValue
= true;
2758 switch (from
->getKindOf()) {
2759 case Expression::KindOfExpressionList
:
2761 ExpressionListPtr
p(spc(ExpressionList
, from
));
2762 switch (p
->getListKind()) {
2763 case ExpressionList::ListKindComma
:
2764 return createTypeAssertions(p
->listValue(), passStmt
, negate
);
2770 case Expression::KindOfSimpleFunctionCall
:
2772 SimpleFunctionCallPtr
p(spc(SimpleFunctionCall
, from
));
2773 ExpressionListPtr
ep(p
->getParams());
2774 StringPosTypeMap::const_iterator
it(
2775 s_type_assertion_map
.find(p
->getName()));
2776 if (it
!= s_type_assertion_map
.end()) {
2777 int pos
= it
->second
.first
;
2778 TypePtr
t(it
->second
.second
);
2779 if (ep
->getCount() - 1 >= pos
&& isAllScalar(ep
, pos
+ 1)) {
2780 ExpressionPtr
a0((*ep
)[pos
]);
2782 SimpleVariablePtr
sv(extractAssertableVariable(a0
));
2786 createTypeAssertionsForKids(from
, 2, passStmt
, negate
);
2787 return newTypeAssertion(sv
, t
);
2791 } else if (p
->getName() == "is_a" &&
2792 (ep
->getCount() >= 2 && isAllScalar(ep
, 1))) {
2793 // special case is_a
2796 createTypeAssertionsForKids(from
, 2, passStmt
, negate
);
2797 return newInstanceOfAssertion((*ep
)[0], (*ep
)[1]);
2799 startIdx
= 2; // params
2802 case Expression::KindOfQOpExpression
:
2804 QOpExpressionPtr
qop(spc(QOpExpression
, from
));
2807 ExpressionPtr
lAfter(
2808 createTypeAssertions(
2809 qop
->getCondition(),
2813 if (negateChild
|| qop
->getYes()) {
2816 insertTypeAssertion(
2818 !negateChild
? qop
->getYes() : qop
->getNo()),
2819 !negateChild
? 1 : 2);
2822 startIdx
= 1; // yes expr
2823 useKidValue
= false;
2826 case Expression::KindOfBinaryOpExpression
:
2828 BinaryOpExpressionPtr
binop(spc(BinaryOpExpression
, from
));
2829 switch (binop
->getOp()) {
2833 // we cannot push the LHS assertion into the expr
2834 // past the RHS assertion, since the RHS assertion could
2835 // have changed the LHS assertion. for example:
2837 // if (is_array($x) && ($x = 5)) { stmt1; }
2839 // All we can do is to push the LHS assertion into the beginning
2840 // of the RHS assertion, and then return the RHS assertion. We
2841 // would need more analysis to do more (eg copy prop of
2845 ExpressionPtr
lhsAfter(
2846 createTypeAssertions(
2850 if (lhsAfter
&& !negateChild
) {
2853 insertTypeAssertion(lhsAfter
, binop
->getExp2()),
2856 ExpressionPtr
rhsAfter(
2857 createTypeAssertions(
2861 return negateChild
? ExpressionPtr() : rhsAfter
;
2869 ExpressionPtr
lhsAfter(
2870 createTypeAssertions(
2874 ExpressionPtr
rhsAfter(
2875 createTypeAssertions(
2879 if (lhsAfter
&& rhsAfter
&& !negateChild1
&& !negateChild2
) {
2880 return orAssertions(lhsAfter
, rhsAfter
);
2882 return ExpressionPtr();
2886 ExpressionPtr
r(newInstanceOfAssertion(
2887 binop
->getExp1(), binop
->getExp2()));
2893 case Expression::KindOfUnaryOpExpression
:
2895 UnaryOpExpressionPtr
unop(spc(UnaryOpExpression
, from
));
2896 switch (unop
->getOp()) {
2900 ExpressionPtr
after(
2901 createTypeAssertions(
2902 unop
->getExpression(), passStmt
, negate
));
2907 // do the default behavior
2912 case Expression::KindOfAssignmentExpression
:
2914 // handle $x = (type) $x explicitly,
2915 // since our current type inference will not be
2916 // able to deal with it optimally
2917 AssignmentExpressionPtr
ap(spc(AssignmentExpression
, from
));
2918 SimpleVariablePtr
sv(dpc(SimpleVariable
, ap
->getVariable()));
2919 UnaryOpExpressionPtr
uop(dpc(UnaryOpExpression
, ap
->getValue()));
2921 TypePtr
castType(uop
->getCastType());
2923 if (SimpleVariablePtr sv0
=
2924 dpc(SimpleVariable
, uop
->getExpression())) {
2925 if (sv
->getName() == sv0
->getName()) {
2927 return newTypeAssertion(sv
, castType
);
2932 useKidValue
= false;
2938 ExpressionPtr
result(
2939 createTypeAssertionsForKids(from
, startIdx
, passStmt
, negate
));
2940 return useKidValue
? result
: ExpressionPtr();
2943 void insertTypeAssertion(
2944 ExpressionPtr assertion
,
2950 switch (stmt
->getKindOf()) {
2951 case Statement::KindOfBlockStatement
:
2953 BlockStatementPtr
blockPtr(spc(BlockStatement
, stmt
));
2954 insertTypeAssertion(assertion
, blockPtr
->getStmts());
2957 case Statement::KindOfStatementList
:
2959 StatementListPtr
slistPtr(spc(StatementList
, stmt
));
2960 slistPtr
->insertElement(
2963 CONSTRUCT_PARAMS(slistPtr
), assertion
)),
2967 case Statement::KindOfExpStatement
:
2969 ExpStatementPtr
es(spc(ExpStatement
, stmt
));
2971 insertTypeAssertion(assertion
, es
->getExpression()));
2972 replaceExpression(es
, rep
, es
->getExpression(), 0);
2975 case Statement::KindOfReturnStatement
:
2977 ReturnStatementPtr
rs(spc(ReturnStatement
, stmt
));
2978 if (rs
->hasRetExp()) {
2980 insertTypeAssertion(assertion
, rs
->getRetExp()));
2981 replaceExpression(rs
, rep
, rs
->getRetExp(), 0);
2986 // this is something like a continue statement,
2987 // in which case we don't do anything
2992 ExpressionPtr
createTypeAssertions(StatementPtr e
) {
2993 if (!e
) return ExpressionPtr();
2994 if (FunctionWalker::SkipRecurse(e
)) return ExpressionPtr();
2996 ExpressionPtr loopCond
;
2997 StatementPtr loopBody
;
2998 std::vector
<ExpressionPtr
> needed
;
2999 switch (e
->getKindOf()) {
3000 case Statement::KindOfIfStatement
:
3002 IfStatementPtr
ifStmt(spc(IfStatement
, e
));
3003 StatementListPtr
branches(ifStmt
->getIfBranches());
3005 for (int i
= 0; i
< branches
->getCount(); i
++) {
3006 IfBranchStatementPtr
branch(
3007 dpc(IfBranchStatement
, (*branches
)[i
]));
3009 if (branch
->getCondition()) {
3012 ExpressionPtr
after(
3013 createTypeAssertions(
3014 branch
->getCondition(), passStmt
, negate
));
3017 insertTypeAssertion(after
, branch
->getStmt());
3019 // insert into the next branch:
3020 // * if a condition exists, put it in the condition.
3021 // * if there is no condition, put it in the body.
3022 // * if this is the last branch, create a branch after
3023 // with no condition, and put it in the body.
3025 if (i
< branches
->getCount() - 1) {
3026 IfBranchStatementPtr
nextBranch(
3027 dpc(IfBranchStatement
, (*branches
)[i
+ 1]));
3029 if (nextBranch
->getCondition()) {
3030 ExpressionPtr
old(nextBranch
->getCondition());
3033 insertTypeAssertion(after
, old
),
3037 // next branch must be the last branch
3038 assert(i
+ 1 == branches
->getCount() - 1);
3039 insertTypeAssertion(after
, nextBranch
->getStmt());
3042 ExpStatementPtr
newExpStmt(
3044 CONSTRUCT_PARAMS(branch
),
3047 IfBranchStatementPtr
newBranch(
3048 new IfBranchStatement(
3049 CONSTRUCT_PARAMS(branch
),
3050 ExpressionPtr(), newExpStmt
));
3052 branches
->addElement(newBranch
);
3059 for (int i
= 0; i
< branches
->getCount(); i
++) {
3060 IfBranchStatementPtr
branch(
3061 dpc(IfBranchStatement
, (*branches
)[i
]));
3063 if (branch
->getStmt()) {
3064 createTypeAssertions(branch
->getStmt());
3069 return ExpressionPtr();
3070 case Statement::KindOfForStatement
: {
3071 ForStatementPtr
fs(static_pointer_cast
<ForStatement
>(e
));
3072 loopCond
= fs
->getCondExp();
3073 loopBody
= fs
->getBody();
3074 needed
.push_back(fs
->getInitExp());
3075 needed
.push_back(fs
->getIncExp());
3078 case Statement::KindOfWhileStatement
: {
3079 WhileStatementPtr
ws(static_pointer_cast
<WhileStatement
>(e
));
3080 loopCond
= ws
->getCondExp();
3081 loopBody
= ws
->getBody();
3084 case Statement::KindOfDoStatement
: {
3085 DoStatementPtr
ds(static_pointer_cast
<DoStatement
>(e
));
3086 loopCond
= ds
->getCondExp();
3087 loopBody
= ds
->getBody();
3095 ExpressionPtr
after(createTypeAssertions(loopCond
, passStmt
, negate
));
3096 if (after
&& !negate
) {
3097 insertTypeAssertion(after
, loopBody
);
3100 for (auto it
= needed
.begin(); it
!= needed
.end(); ++it
) {
3101 ExpressionPtr
k(dpc(Expression
, *it
));
3105 createTypeAssertions(k
, passStmt
, negate
);
3108 createTypeAssertions(loopBody
);
3110 return ExpressionPtr();
3111 case Statement::KindOfStatementList
:
3113 StatementListPtr
slist(spc(StatementList
, e
));
3115 while (i
< slist
->getCount()) {
3116 ExpressionPtr
next(createTypeAssertions((*slist
)[i
]));
3118 insertTypeAssertion(next
, slist
, i
+ 1);
3119 i
+= 2; // skip over the inserted node
3125 return ExpressionPtr();
3126 case Statement::KindOfExpStatement
:
3128 ExpStatementPtr
es(dpc(ExpStatement
, e
));
3131 ExpressionPtr
after(
3132 createTypeAssertions(es
->getExpression(), passStmt
, negate
));
3133 return passStmt
&& !negate
? after
: ExpressionPtr();
3138 for (int i
= 0; i
< e
->getKidCount(); i
++) {
3139 ConstructPtr
kid(e
->getNthKid(i
));
3141 if (StatementPtr s
= dpc(Statement
, kid
)) {
3142 createTypeAssertions(s
);
3143 } else if (ExpressionPtr e
= dpc(Expression
, kid
)) {
3146 createTypeAssertions(e
, passStmt
, negate
);
3151 return ExpressionPtr();
3156 TypeAssertionInserter::StringPosTypeMap
3157 TypeAssertionInserter::s_type_assertion_map
;
3159 TypeAssertionInserter::s_type_assertion_map_mutex
;
3161 void TypeAssertionInserter::BuildAssertionMap() {
3162 Lock
lock(s_type_assertion_map_mutex
);
3163 if (s_type_assertion_map
.empty()) {
3164 s_type_assertion_map
["is_array"] = PosType(0, Type::Array
);
3165 s_type_assertion_map
["is_string"] = PosType(0, Type::String
);
3166 s_type_assertion_map
["is_object"] = PosType(0, Type::Object
);
3168 s_type_assertion_map
["is_int"] = PosType(0, Type::Int64
);
3169 s_type_assertion_map
["is_integer"] = PosType(0, Type::Int64
);
3170 s_type_assertion_map
["is_long"] = PosType(0, Type::Int64
);
3172 s_type_assertion_map
["is_double"] = PosType(0, Type::Double
);
3173 s_type_assertion_map
["is_float"] = PosType(0, Type::Double
);
3174 s_type_assertion_map
["is_real"] = PosType(0, Type::Double
);
3176 s_type_assertion_map
["is_bool"] = PosType(0, Type::Boolean
);
3178 s_type_assertion_map
["is_numeric"] = PosType(0, Type::Numeric
);
3180 s_type_assertion_map
["in_array"] = PosType(1, Type::Array
);
3182 // even though the PHP docs say that in PHP 5.3, this function
3183 // only accepts an array for the search, Zend PHP 5.3 still
3184 // accepts objects. Quite a bummer.
3185 s_type_assertion_map
["array_key_exists"] =
3189 (Type::KindOf
)(Type::KindOfArray
|Type::KindOfObject
))));
3193 class TypeAssertionRemover
{
3195 TypeAssertionRemover() : m_changed(false) {}
3196 bool walk(StatementPtr stmt
) {
3198 removeTypeAssertions(stmt
);
3205 void safeRepValue(ConstructPtr parent
, int i
,
3206 ExpressionPtr orig
, ExpressionPtr rep
) {
3207 if (orig
== rep
) return;
3209 return parent
->setNthKid(i
, orig
->replaceValue(rep
));
3212 void safeRepValue(ConstructPtr parent
, int i
,
3213 ConstructPtr orig
, ConstructPtr rep
) {
3214 if (orig
== rep
) return;
3216 return parent
->setNthKid(i
, rep
);
3220 * Returns the replacement node for from
3222 ConstructPtr
removeTypeAssertions(ConstructPtr from
) {
3223 if (!from
) return ConstructPtr();
3224 if (StatementPtr s
= dpc(Statement
, from
)) {
3225 return removeTypeAssertions(s
);
3226 } else if (ExpressionPtr e
= dpc(Expression
, from
)) {
3227 return removeTypeAssertions(e
);
3230 return ConstructPtr();
3234 ExpressionPtr
restoreExpType(ExpressionPtr orig
, ExpressionPtr rep
) {
3235 rep
->setExpectedType(orig
->getExpectedType());
3239 ExpressionPtr
removeTypeAssertions(ExpressionPtr from
) {
3240 if (!from
) return ExpressionPtr();
3241 switch (from
->getKindOf()) {
3242 case Expression::KindOfExpressionList
:
3244 ExpressionListPtr
p(spc(ExpressionList
, from
));
3245 if (p
->getListKind() ==
3246 ExpressionList::ListKindComma
) {
3247 for (int i
= 0; i
< p
->getCount(); i
++) {
3248 ExpressionPtr
c((*p
)[i
]);
3249 ExpressionPtr
rep(removeTypeAssertions(c
));
3250 if (!rep
) p
->removeElement(i
--);
3251 else safeRepValue(p
, i
, c
, rep
);
3253 if (p
->isNoRemove()) {
3254 if (p
->getCount() == 0) return ExpressionPtr();
3255 if (p
->getCount() == 1) return restoreExpType(p
, (*p
)[0]);
3260 case Expression::KindOfSimpleVariable
:
3261 if (from
->isNoRemove()) return ExpressionPtr();
3266 for (int i
= 0; i
< from
->getKidCount(); i
++) {
3267 ExpressionPtr
c(from
->getNthExpr(i
));
3268 ExpressionPtr
rep(removeTypeAssertions(c
));
3269 safeRepValue(from
, i
, c
, rep
);
3274 StatementPtr
removeTypeAssertions(StatementPtr from
) {
3275 if (!from
) return from
;
3276 if (FunctionWalker::SkipRecurse(from
)) return from
;
3278 switch (from
->getKindOf()) {
3279 case Statement::KindOfExpStatement
:
3281 ExpStatementPtr
p(spc(ExpStatement
, from
));
3282 ExpressionPtr
rep(removeTypeAssertions(p
->getExpression()));
3283 if (!rep
) return StatementPtr();
3284 else safeRepValue(p
, 0, p
->getExpression(), rep
);
3287 case Statement::KindOfStatementList
:
3289 StatementListPtr
p(spc(StatementList
, from
));
3290 for (int i
= 0; i
< p
->getKidCount(); i
++) {
3291 StatementPtr
s((*p
)[i
]);
3292 StatementPtr
rep(removeTypeAssertions(s
));
3293 if (!rep
) p
->removeElement(i
--);
3294 else safeRepValue(from
, i
, s
, rep
);
3300 for (int i
= 0; i
< from
->getKidCount(); i
++) {
3301 ConstructPtr
c(from
->getNthKid(i
));
3302 ConstructPtr
rep(removeTypeAssertions(c
));
3303 safeRepValue(from
, i
, c
, rep
);
3313 static bool isNewResult(ExpressionPtr e
) {
3314 if (!e
) return false;
3315 if (e
->is(Expression::KindOfNewObjectExpression
)) return true;
3316 if (e
->is(Expression::KindOfAssignmentExpression
)) {
3317 return isNewResult(spc(AssignmentExpression
, e
)->getValue());
3319 if (e
->is(Expression::KindOfExpressionList
)) {
3320 return isNewResult(spc(ExpressionList
, e
)->listValue());
3325 class ConstructTagger
: public DataFlowWalker
{
3327 ConstructTagger(ControlFlowGraph
*g
,
3328 std::map
<std::string
,int> &gidMap
) :
3329 DataFlowWalker(g
), m_gidMap(gidMap
) {}
3331 void walk(MethodStatementPtr m
) {
3332 DataFlowWalker::walk(*this);
3333 ControlBlock
*b
= m_graph
.getDfBlock(1);
3334 std::map
<std::string
,int>::iterator it
= m_gidMap
.find("v:this");
3335 if (m
->getOrigGeneratorFunc()) {
3336 BitOps::set(m_gidMap
.size(), b
->getRow(DataFlow::PRefIn
),
3338 BitOps::set(m_gidMap
.size(), b
->getRow(DataFlow::PInitIn
),
3341 if (it
!= m_gidMap
.end() && it
->second
) {
3342 b
->setBit(DataFlow::PRefIn
, it
->second
);
3343 b
->setBit(DataFlow::PInitIn
, it
->second
);
3345 updateParamInfo(m
->getParams(), Option::HardTypeHints
);
3346 updateParamInfo(m
->getFunctionScope()->getClosureVars(), false);
3350 void updateParamInfo(ExpressionListPtr el
, bool useDefaults
) {
3352 ControlBlock
*b
= m_graph
.getDfBlock(1);
3353 for (int i
= el
->getCount(); i
--; ) {
3354 ParameterExpressionPtr p
=
3355 static_pointer_cast
<ParameterExpression
>((*el
)[i
]);
3356 std::map
<std::string
,int>::iterator it
=
3357 m_gidMap
.find("v:" + p
->getName());
3358 if (it
!= m_gidMap
.end() && it
->second
) {
3359 // NB: this is unsound if the user error handler swallows a
3360 // parameter typehint failure. It's opt-in via compiler
3362 if (useDefaults
&& p
->hasTypeHint() && !p
->defaultValue()) {
3363 b
->setBit(DataFlow::AvailIn
, it
->second
);
3365 b
->setBit(DataFlow::PRefIn
, it
->second
);
3366 b
->setBit(DataFlow::PInitIn
, it
->second
);
3371 void processAccess(ExpressionPtr e
) {
3372 int id
= e
->getCanonID();
3374 if (e
->isThis() && e
->getAssertedType()) {
3377 if (m_block
->getBit(DataFlow::Available
, id
)) {
3379 e
->clearAnticipated();
3381 m_block
->setBit(DataFlow::Available
, id
);
3382 e
->setAnticipated();
3385 bool set
= true, maybeRef
= true;
3386 SimpleVariablePtr sv
;
3387 if (e
->is(Expression::KindOfSimpleVariable
)) {
3388 sv
= spc(SimpleVariable
, e
);
3389 set
= (e
->isThis() && e
->hasContext(Expression::ObjectContext
));
3390 if (e
->getAssertedType()) {
3395 if (e
->is(Expression::KindOfObjectMethodExpression
)) {
3396 ExpressionPtr
a(spc(ObjectMethodExpression
, e
)->getObject());
3398 if (a
->is(Expression::KindOfObjectPropertyExpression
)) {
3399 a
= spc(ObjectPropertyExpression
, a
)->getObject();
3400 } else if (a
->is(Expression::KindOfArrayElementExpression
)) {
3401 a
= spc(ArrayElementExpression
, a
)->getVariable();
3402 } else if (a
->is(Expression::KindOfAssignmentExpression
)) {
3403 a
= spc(AssignmentExpression
, a
)->getValue();
3404 } else if (a
->is(Expression::KindOfExpressionList
)) {
3405 a
= spc(ExpressionList
, a
)->listValue();
3410 if (a
->is(Expression::KindOfSimpleVariable
)) {
3411 sv
= spc(SimpleVariable
, a
);
3413 } else if (e
->is(Expression::KindOfObjectPropertyExpression
)) {
3414 ObjectPropertyExpressionPtr
op(spc(ObjectPropertyExpression
, e
));
3415 if (op
->getObject()->is(Expression::KindOfSimpleVariable
)) {
3416 sv
= spc(SimpleVariable
, op
->getObject());
3419 } else if (e
->is(Expression::KindOfAssignmentExpression
)) {
3420 AssignmentExpressionPtr
ae(spc(AssignmentExpression
, e
));
3421 if (ae
->getVariable()->is(Expression::KindOfSimpleVariable
)) {
3422 sv
= spc(SimpleVariable
, ae
->getVariable());
3423 set
= isNewResult(ae
->getValue());
3424 if (!sv
->couldBeAliased() &&
3425 (ae
->getValue()->isScalar() ||
3426 (ae
->getValue()->getActualType() &&
3427 ae
->getValue()->getActualType()->getKindOf() <
3428 Type::KindOfString
))) {
3433 if (sv
&& sv
->isThis()) sv
.reset();
3436 id
= m_gidMap
["v:" + sv
->getName()];
3439 sv
->clearAnticipated();
3440 if (m_block
->getBit(DataFlow::Killed
, id
)) {
3445 if (m_block
->getBit(DataFlow::Referenced
, id
)) {
3446 sv
->setRefCounted();
3449 if (m_block
->getBit(DataFlow::Inited
, id
)) {
3453 if (sv
->hasAllContext(Expression::UnsetContext
|
3454 Expression::LValue
)) {
3455 m_block
->setBit(DataFlow::Available
, id
, false);
3456 m_block
->setBit(DataFlow::Altered
, id
, true);
3457 m_block
->setBit(DataFlow::Killed
, id
, true);
3458 m_block
->setBit(DataFlow::Referenced
, id
, false);
3459 m_block
->setBit(DataFlow::Inited
, id
, false);
3462 bool ref
= sv
->hasAnyContext(Expression::RefValue
|
3463 Expression::InvokeArgument
|
3464 Expression::DeepReference
|
3465 Expression::DeepAssignmentLHS
|
3466 Expression::DeepOprLValue
);
3469 sv
->hasAllContext(Expression::Declaration
) ||
3470 sv
->hasAnyContext(Expression::AssignmentLHS
|
3471 Expression::OprLValue
) ||
3472 (!ref
&& sv
->hasContext(Expression::LValue
));
3475 m_block
->setBit(DataFlow::Available
, id
, false);
3476 m_block
->setBit(DataFlow::Altered
, id
, true);
3479 m_block
->setBit(DataFlow::Referenced
, id
, true);
3480 m_block
->setBit(DataFlow::Inited
, id
, true);
3484 if (TypePtr act
= sv
->getActualType()) {
3485 if (sv
->hasContext(Expression::ObjectContext
)) {
3486 if (act
->is(Type::KindOfObject
)) kill
= false;
3487 } else if (sv
->hasContext(Expression::AccessContext
)) {
3488 if (act
->is(Type::KindOfArray
)) kill
= false;
3493 m_block
->setBit(DataFlow::Killed
, id
, true);
3498 if (!sv
->couldBeAliased()) {
3499 if (m_block
->getBit(DataFlow::Available
, id
)) {
3502 if (!m_block
->getBit(DataFlow::Altered
, id
)) {
3503 sv
->setAnticipated();
3505 if (set
&& !sv
->hasAnyContext(Expression::ExistContext
|
3506 Expression::UnsetContext
)) {
3507 m_block
->setBit(DataFlow::Available
, id
, true);
3513 assert(m_block
->getBit(DataFlow::Killed
, id
));
3514 m_block
->setBit(DataFlow::Referenced
, id
, false);
3516 if (set
&& !sv
->hasAnyContext(Expression::ExistContext
|
3517 Expression::UnsetContext
)) {
3518 m_block
->setBit(DataFlow::Available
, id
, true);
3526 int after(ConstructRawPtr cp
) {
3527 if (ReturnStatementPtr rs
= dynamic_pointer_cast
<ReturnStatement
>(cp
)) {
3528 int id
= m_gidMap
["v:this"];
3529 if (id
&& m_block
->getBit(DataFlow::Available
, id
)) {
3533 return DataFlowWalker::after(cp
);
3536 std::map
<std::string
,int> &m_gidMap
;
3539 class ConstructMarker
: public DataFlowWalker
{
3541 ConstructMarker(ControlFlowGraph
*g
, std::map
<std::string
,int> &gidMap
) :
3542 DataFlowWalker(g
), m_gidMap(gidMap
),
3543 m_top(g
->getMethod()->getStmts()) {}
3546 DataFlowWalker::walk(*this);
3549 void processAccess(ExpressionPtr e
) {
3550 int id
= e
->getCanonID();
3551 if (!id
&& e
->is(Expression::KindOfSimpleVariable
) &&
3552 (e
->isAnticipated() || !e
->isKilled())) {
3553 id
= m_gidMap
["v:" + static_pointer_cast
<SimpleVariable
>(e
)->getName()];
3556 if (!m_block
->getDfn()) return;
3557 if (e
->isAnticipated() && m_block
->getBit(DataFlow::AvailIn
, id
)) {
3560 if (e
->is(Expression::KindOfSimpleVariable
) && !e
->isKilled()) {
3561 if (m_block
->getBit(DataFlow::PRefIn
, id
)) {
3564 e
->clearRefCounted();
3566 if (m_block
->getBit(DataFlow::PInitIn
, id
)) {
3575 int after(ConstructRawPtr cp
) {
3577 static_pointer_cast
<Statement
>(cp
)->is(
3578 Statement::KindOfReturnStatement
)) {
3579 if (m_block
->getDfn()) {
3580 int id
= m_gidMap
["v:this"];
3581 if (id
&& m_block
->getBit(DataFlow::AvailOut
, id
)) {
3587 if (auto rs
= dynamic_pointer_cast
<ReturnStatement
>(cp
)) {
3588 std::vector
<std::string
> lnames
;
3589 VariableTableConstPtr vars
= cp
->getFunctionScope()->getVariables();
3590 vars
->getLocalVariableNames(lnames
);
3591 for (auto& l
: lnames
) {
3592 int id
= m_gidMap
["v:" + l
];
3593 if (id
&& !m_block
->getBit(DataFlow::PInitOut
, id
)) {
3594 rs
->addNonRefcounted(l
);
3596 auto sym
= vars
->getSymbol(l
);
3597 auto dt
= vars
->getFinalType(l
)->getDataType();
3598 if (!sym
->isStatic()
3599 && !IS_REFCOUNTED_TYPE(dt
) && dt
!= KindOfUnknown
) {
3600 rs
->addNonRefcounted(l
);
3606 return DataFlowWalker::after(cp
);
3609 std::map
<std::string
,int> &m_gidMap
;
3613 class Propagater
: public ControlFlowGraphWalker
{
3615 Propagater(ControlFlowGraph
*g
, ExprDict
&d
, bool doTypeProp
) :
3616 ControlFlowGraphWalker(g
), m_dict(d
),
3617 m_changed(false), m_doTypeProp(doTypeProp
) {}
3619 bool walk() { ControlFlowGraphWalker::walk(*this); return m_changed
; }
3620 int afterEach(ConstructRawPtr p
, int i
, ConstructPtr kid
) {
3621 if (ExpressionRawPtr e
= boost::dynamic_pointer_cast
<Expression
>(kid
)) {
3622 if (e
->isTypeAssertion()) return WalkContinue
; // nothing to do
3625 e
->isAnticipated() &&
3626 !(e
->getContext() & (Expression::LValue
|
3627 Expression::OprLValue
|
3628 Expression::AssignmentLHS
|
3629 Expression::RefValue
|
3630 Expression::UnsetContext
|
3631 Expression::DeepReference
));
3633 if (ExpressionPtr rep
= m_dict
.propagate(e
)) {
3635 rep
= e
->replaceValue(rep
->clone());
3636 p
->setNthKid(i
, rep
);
3637 return WalkContinue
;
3641 if (m_doTypeProp
&& e
->isAnticipated()) {
3642 TypePtr t
= m_dict
.propagateType(e
);
3643 if (!t
) return WalkContinue
;
3645 // $x[0] = ... where $x is not referenced
3646 // should be allowed to grab the type assertion
3647 // if it is an array assertion
3648 (t
->is(Type::KindOfArray
) &&
3649 e
->is(Expression::KindOfSimpleVariable
) &&
3650 e
->hasContext(Expression::AccessContext
) &&
3651 !spc(SimpleVariable
, e
)->couldBeAliased())) {
3652 e
->setAssertedType(t
);
3657 return WalkContinue
;
3660 void beforeBlock(ControlBlock
*b
) {
3661 m_dict
.beforePropagate(b
);
3669 void AliasManager::doFinal(MethodStatementPtr m
) {
3670 FunctionScopeRawPtr func
= m
->getFunctionScope();
3671 if (func
->isRefReturn()) {
3673 } else if (m_nrvoFix
> 0) {
3674 Symbol
*sym
= m_variables
->getSymbol(m_returnVar
);
3675 if (sym
&& !sym
->isParameter() &&
3676 (m_wildRefs
|| sym
->isReferenced() ||
3677 ((sym
->isGlobal() || sym
->isStatic()) &&
3678 m_variables
->needLocalCopy(sym
)))) {
3685 func
->setNRVOFix(m_nrvoFix
> 0);
3687 if (Option::StringLoopOpts
&& !m_wildRefs
) {
3688 stringOptsRecur(m
->getStmts());
3692 void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m
) {
3693 always_assert(m_graph
!= nullptr);
3695 // bail out for pseudomain context
3696 if (m
->getScope()->inPseudoMain()) return;
3700 AttributeTagger
<RefDict
> rt(m_graph
, rd
);
3701 RefDictWalker
rdw(m_graph
);
3703 // referenced analysis
3706 DataFlow::ComputePartialReferenced(*m_graph
);
3715 DataFlow::ComputePartialNeeded(*m_graph
);
3719 int AliasManager::copyProp(MethodStatementPtr m
) {
3720 if (m_graph
== nullptr) createCFG(m
);
3722 performReferencedAndNeededAnalysis(m
);
3727 AttributeTagger
<ExprDict
> at(m_graph
, ed
);
3731 DataFlow::ComputeAvailable(*m_graph
);
3732 DataFlow::ComputeAnticipated(*m_graph
);
3734 if (Option::DumpAst
) m_graph
->dump(m_arp
);
3736 Propagater
prop(m_graph
, ed
, m_preOpt
);
3737 bool ret
= prop
.walk();
3742 void AliasManager::deleteCFG() {
3743 assert(m_graph
!= nullptr);
3748 void AliasManager::createCFG(MethodStatementPtr m
) {
3749 assert(m_graph
== nullptr);
3750 m_graph
= ControlFlowGraph::buildControlFlow(m
);
3753 void AliasManager::insertTypeAssertions(AnalysisResultConstPtr ar
,
3754 MethodStatementPtr m
) {
3755 TypeAssertionInserter
i(ar
);
3756 i
.walk(m
->getStmts());
3758 if (Option::ControlFlow
&& Option::DumpAst
) {
3759 if (m_graph
!= nullptr) deleteCFG();
3761 printf("-------- BEGIN INSERTED -----------\n");
3762 m_graph
->dump(m_arp
);
3763 printf("-------- END INSERTED -----------\n");
3768 void AliasManager::removeTypeAssertions(AnalysisResultConstPtr ar
,
3769 MethodStatementPtr m
) {
3770 TypeAssertionRemover r
;
3771 r
.walk(m
->getStmts());
3773 if (Option::ControlFlow
&& Option::DumpAst
) {
3774 if (m_graph
!= nullptr) deleteCFG();
3776 printf("-------- BEGIN REMOVED -----------\n");
3777 m_graph
->dump(m_arp
);
3778 printf("-------- END REMOVED -----------\n");
3783 int AliasManager::optimize(AnalysisResultConstPtr ar
, MethodStatementPtr m
) {
3784 m_hasTypeAssertions
= false;
3787 bool runCanon
= Option::LocalCopyProp
|| Option::EliminateDeadCode
;
3789 if (runCanon
&& m_preOpt
) {
3790 if (m_hasTypeAssertions
) removeTypeAssertions(ar
, m
);
3791 insertTypeAssertions(ar
, m
);
3794 if (runCanon
&& m_postOpt
&& m_hasTypeAssertions
) {
3795 removeTypeAssertions(ar
, m
);
3798 if (!m_hasDeadStore
&& Option::CopyProp
) {
3799 if (copyProp(m
)) return 1;
3802 if (m_graph
!= nullptr) deleteCFG();
3804 m_hasChainRoot
= false;
3807 for (int i
= 0, nkid
= m
->getKidCount(); i
< nkid
; i
++) {
3812 canonicalizeKid(m
, m
->getNthKid(i
), i
);
3816 if (m_hasChainRoot
&& m_postOpt
) {
3817 // need to do possible invalidation for label statements
3818 invalidateChainRoots(m
->getStmts());
3822 if (!m_replaced
&& !m_changes
&& m_postOpt
&& !Option::ControlFlow
) {
3826 return m_replaced
? -1 : m_changes
? 1 : 0;
3829 void AliasManager::finalSetup(AnalysisResultConstPtr ar
, MethodStatementPtr m
) {
3830 if (Option::ControlFlow
) {
3831 m_graph
= ControlFlowGraph::buildControlFlow(m
);
3836 if (!m_inPseudoMain
&&
3837 !m_variables
->getAttribute(VariableTable::ContainsLDynamicVariable
)) {
3838 for (std::map
<string
,SimpleVariablePtr
>::iterator it
=
3839 m_objMap
.begin(), end
= m_objMap
.end(); it
!= end
; ++it
) {
3840 SimpleVariablePtr sv
= it
->second
;
3841 const Symbol
*sym
= sv
->getSymbol();
3842 int &id
= m_gidMap
["v:"+sym
->getName()];
3844 id
= m_gidMap
.size();
3849 static int rows
[] = {
3850 DataFlow::Available
, DataFlow::Altered
,
3851 DataFlow::Inited
, DataFlow::Referenced
, DataFlow::Killed
,
3852 DataFlow::AvailIn
, DataFlow::AvailOut
,
3853 DataFlow::PInitIn
, DataFlow::PInitOut
,
3854 DataFlow::PRefIn
, DataFlow::PRefOut
3856 m_graph
->allocateDataFlow(m_gidMap
.size()+1,
3857 sizeof(rows
)/sizeof(rows
[0]), rows
);
3860 ConstructTagger
ct(m_graph
, m_gidMap
);
3863 DataFlow::ComputeAvailable(*m_graph
);
3864 DataFlow::ComputePartialReferenced(*m_graph
);
3865 DataFlow::ComputePartialInited(*m_graph
);
3867 ConstructMarker
cm(m_graph
, m_gidMap
);
3870 if (Option::VariableCoalescing
&&
3872 !m_variables
->getAttribute(VariableTable::ContainsDynamicVariable
)) {
3874 performReferencedAndNeededAnalysis(m
);
3879 AttributeTagger
<LiveDict
> lt(m_graph
, ld
);
3883 DataFlow::ComputePartialAvailable(*m_graph
);
3884 DataFlow::ComputePartialAnticipated(*m_graph
);
3885 DataFlow::ComputeUsed(*m_graph
);
3886 DataFlow::ComputePartialDying(*m_graph
);
3888 if (Option::DumpAst
) m_graph
->dump(ar
);
3890 ld
.buildConflicts();
3891 if (ld
.color(Type::Variant
) ||
3892 ld
.color(Type::String
) ||
3893 ld
.color(Type::Numeric
) ||
3894 ld
.color(Type::Primitive
)) {
3900 if (Option::DumpAst
) m_graph
->dump(ar
);
3908 void AliasManager::invalidateChainRoots(StatementPtr s
) {
3910 if (FunctionWalker::SkipRecurse(s
)) return;
3911 switch (s
->getKindOf()) {
3912 case Statement::KindOfStatementList
:
3914 StatementListPtr
slist(spc(StatementList
, s
));
3915 // start from the last statement -
3916 // if we find a child stmt with
3917 // a reachable label, we must invalidate
3918 // all statements before
3919 bool disable
= false;
3920 for (int i
= s
->getKidCount(); i
--; ) {
3921 StatementPtr
kid((*slist
)[i
]);
3922 invalidateChainRoots(kid
);
3923 if (!disable
&& kid
->hasReachableLabel()) {
3926 if (disable
) disableCSE(kid
);
3930 case Statement::KindOfDoStatement
:
3932 // need to disable CSE in the top level body
3933 // otherwise we'd have to declare all CSE temps like:
3935 // do { ... } while (cond);
3936 DoStatementPtr
ds(static_pointer_cast
<DoStatement
>(s
));
3937 disableCSE(ds
->getBody());
3941 for (int i
= s
->getKidCount(); i
--; ) {
3942 invalidateChainRoots(s
->getNthStmt(i
));
3948 void AliasManager::nullSafeDisableCSE(StatementPtr parent
, ExpressionPtr kid
) {
3954 void AliasManager::disableCSE(StatementPtr s
) {
3956 switch (s
->getKindOf()) {
3957 case Statement::KindOfIfBranchStatement
: {
3958 IfBranchStatementPtr
is(static_pointer_cast
<IfBranchStatement
>(s
));
3959 nullSafeDisableCSE(s
, is
->getCondition());
3962 case Statement::KindOfSwitchStatement
: {
3963 SwitchStatementPtr
ss(static_pointer_cast
<SwitchStatement
>(s
));
3964 nullSafeDisableCSE(s
, ss
->getExp());
3967 case Statement::KindOfForStatement
: {
3968 ForStatementPtr
fs(static_pointer_cast
<ForStatement
>(s
));
3969 nullSafeDisableCSE(s
, fs
->getInitExp());
3970 nullSafeDisableCSE(s
, fs
->getCondExp());
3971 nullSafeDisableCSE(s
, fs
->getIncExp());
3974 case Statement::KindOfForEachStatement
: {
3975 ForEachStatementPtr
fs(static_pointer_cast
<ForEachStatement
>(s
));
3976 nullSafeDisableCSE(s
, fs
->getArrayExp());
3977 nullSafeDisableCSE(s
, fs
->getNameExp());
3978 nullSafeDisableCSE(s
, fs
->getValueExp());
3981 case Statement::KindOfWhileStatement
: {
3982 WhileStatementPtr
ws(static_pointer_cast
<WhileStatement
>(s
));
3983 nullSafeDisableCSE(s
, ws
->getCondExp());
3986 case Statement::KindOfDoStatement
: {
3987 DoStatementPtr
ds(static_pointer_cast
<DoStatement
>(s
));
3988 nullSafeDisableCSE(s
, ds
->getCondExp());
3992 for (int i
= s
->getKidCount(); i
--; ) {
3993 ConstructPtr
c(s
->getNthKid(i
));
3994 if (StatementPtr skid
= dpc(Statement
, c
)) {
3997 nullSafeDisableCSE(s
, dpc(Expression
, c
));
4004 AliasManager::LoopInfo::LoopInfo(StatementPtr s
) :
4005 m_stmt(s
), m_valid(!s
->is(Statement::KindOfSwitchStatement
)) {
4008 void AliasManager::pushStringScope(StatementPtr s
) {
4009 m_loopInfo
.push_back(LoopInfo(s
));
4010 if (LoopStatementPtr cur
= dpc(LoopStatement
,s
)) {
4011 cur
->clearStringBufs();
4015 void AliasManager::popStringScope(StatementPtr s
) {
4016 size_t sz
= m_loopInfo
.size();
4018 LoopInfo
&li1
= m_loopInfo
.back();
4019 always_assert(li1
.m_stmt
== s
);
4020 if (li1
.m_candidates
.size() && li1
.m_valid
) {
4021 for (unsigned i
= li1
.m_inner
.size(); i
--; ) {
4022 if (LoopStatementPtr inner
= dpc(LoopStatement
, li1
.m_inner
[i
])) {
4023 for (StringSet::iterator it
= li1
.m_candidates
.begin(),
4024 end
= li1
.m_candidates
.end(); it
!= end
; ++it
) {
4025 inner
->removeStringBuf(*it
);
4030 if (LoopStatementPtr cur
= dpc(LoopStatement
, li1
.m_stmt
)) {
4031 for (StringSet::iterator it
= li1
.m_candidates
.begin(),
4032 end
= li1
.m_candidates
.end(); it
!= end
; ++it
) {
4033 cur
->addStringBuf(*it
);
4039 LoopInfo
&li2
= m_loopInfo
[sz
-2];
4040 if (li1
.m_candidates
.size()) {
4041 for (StringSet::iterator it
= li1
.m_candidates
.begin(),
4042 end
= li1
.m_candidates
.end(); it
!= end
; ++it
) {
4043 if (li2
.m_excluded
.find(*it
) == li2
.m_excluded
.end()) {
4044 li2
.m_candidates
.insert(*it
);
4047 li2
.m_inner
.push_back(s
);
4049 for (StringSet::iterator it
= li1
.m_excluded
.begin(),
4050 end
= li1
.m_excluded
.end(); it
!= end
; ++it
) {
4051 li2
.m_excluded
.insert(*it
);
4052 li2
.m_candidates
.erase(*it
);
4054 for (unsigned i
= li1
.m_inner
.size(); i
--; ) {
4055 if (LoopStatementPtr inner
= dpc(LoopStatement
, li1
.m_inner
[i
])) {
4056 if (inner
->numStringBufs()) {
4057 li2
.m_inner
.push_back(inner
);
4063 m_loopInfo
.pop_back();
4066 void AliasManager::stringOptsRecur(ExpressionPtr e
, bool ok
) {
4068 if (!m_loopInfo
.size()) return;
4069 Expression::KindOf etype
= e
->getKindOf();
4071 case Expression::KindOfBinaryOpExpression
:
4073 BinaryOpExpressionPtr
b(spc(BinaryOpExpression
,e
));
4074 stringOptsRecur(b
->getExp2(), false);
4075 if (ok
&& b
->getOp() == T_CONCAT_EQUAL
) {
4076 ExpressionPtr var
= b
->getExp1();
4077 if (var
->is(Expression::KindOfSimpleVariable
)) {
4078 SimpleVariablePtr
s(spc(SimpleVariable
,var
));
4079 if (!s
->couldBeAliased()) {
4080 LoopInfo
&li
= m_loopInfo
.back();
4081 if (li
.m_excluded
.find(s
->getName()) ==
4082 li
.m_excluded
.end()) {
4083 li
.m_candidates
.insert(s
->getName());
4089 stringOptsRecur(b
->getExp1(), false);
4092 case Expression::KindOfExpressionList
:
4094 ExpressionListPtr
el(spc(ExpressionList
,e
));
4095 if (el
->getListKind() != ExpressionList::ListKindParam
) {
4096 int n
= el
->getCount();
4097 int chk
= el
->getListKind() == ExpressionList::ListKindLeft
?
4099 for (int i
= 0; i
< n
; i
++) {
4100 stringOptsRecur((*el
)[i
], i
!= chk
|| ok
);
4106 case Expression::KindOfSimpleVariable
:
4108 SimpleVariablePtr
s(spc(SimpleVariable
,e
));
4109 LoopInfo
&li
= m_loopInfo
.back();
4110 li
.m_excluded
.insert(s
->getName());
4111 li
.m_candidates
.erase(s
->getName());
4118 for (int i
= 0, n
= e
->getKidCount(); i
< n
; i
++) {
4119 stringOptsRecur(e
->getNthExpr(i
), false);
4123 void AliasManager::stringOptsRecur(StatementPtr s
) {
4126 // Dont handle nested functions
4127 // they will be dealt with by another
4129 if (FunctionWalker::SkipRecurse(s
)) return;
4132 Statement::KindOf stype
= s
->getKindOf();
4134 case Statement::KindOfSwitchStatement
:
4135 if (m_loopInfo
.size()) {
4141 case Statement::KindOfForStatement
: {
4142 ForStatementPtr fs
= spc(ForStatement
, s
);
4143 stringOptsRecur(fs
->getInitExp(), true);
4145 stringOptsRecur(fs
->getCondExp(), false);
4146 stringOptsRecur(fs
->getBody());
4147 stringOptsRecur(fs
->getIncExp(), true);
4151 case Statement::KindOfWhileStatement
: {
4152 WhileStatementPtr ws
= spc(WhileStatement
, s
);
4154 stringOptsRecur(ws
->getCondExp(), false);
4155 stringOptsRecur(ws
->getBody());
4159 case Statement::KindOfDoStatement
: {
4160 DoStatementPtr ds
= spc(DoStatement
, s
);
4162 stringOptsRecur(ds
->getBody());
4163 stringOptsRecur(ds
->getCondExp(), false);
4167 case Statement::KindOfForEachStatement
: {
4168 ForEachStatementPtr fs
= spc(ForEachStatement
, s
);
4169 stringOptsRecur(fs
->getArrayExp(), false);
4170 stringOptsRecur(fs
->getNameExp(), false);
4171 stringOptsRecur(fs
->getValueExp(), false);
4173 stringOptsRecur(fs
->getBody());
4177 case Statement::KindOfExpStatement
:
4178 stringOptsRecur(spc(ExpStatement
,s
)->getExpression(), true);
4181 case Statement::KindOfBreakStatement
:
4183 BreakStatementPtr b
= spc(BreakStatement
, s
);
4184 int64_t depth
= b
->getDepth();
4186 int64_t s
= m_loopInfo
.size() - 1;
4188 if (!depth
|| depth
> s
) depth
= s
;
4190 m_loopInfo
[s
- depth
].m_valid
= false;
4201 int nkid
= s
->getKidCount();
4202 for (int i
= 0; i
< nkid
; i
++) {
4203 ConstructPtr cp
= s
->getNthKid(i
);
4207 if (StatementPtr skid
= dpc(Statement
, cp
)) {
4208 stringOptsRecur(skid
);
4210 stringOptsRecur(spc(Expression
, cp
), false);
4218 void AliasManager::beginInExpression(StatementPtr parent
, ExpressionPtr kid
) {
4220 if (m_exprIdx
== -1) {
4221 assert(!m_exprParent
);
4222 m_exprIdx
= m_accessList
.size();
4223 m_exprParent
= parent
;
4228 void AliasManager::endInExpression(StatementPtr requestor
) {
4230 if (m_exprIdx
!= -1) {
4231 assert(m_exprIdx
>= 0 && m_exprParent
);
4232 if (requestor
== m_exprParent
) {
4234 m_exprParent
.reset();
4240 void AliasManager::markAllLocalExprAltered(ExpressionPtr e
) {
4241 if (!m_postOpt
) return;
4242 assert(isInExpression());
4243 assert(m_exprIdx
<= (int)m_accessList
.size());
4244 e
->setLocalExprAltered();
4245 ExpressionPtrList::reverse_iterator
it(m_accessList
.rbegin());
4246 int curIdx
= m_accessList
.size() - 1;
4247 bool found
= m_exprBeginStack
.empty();
4248 for (; curIdx
>= m_exprIdx
; --curIdx
, ++it
) {
4249 ExpressionPtr
p(*it
);
4250 if (!found
&& p
== m_exprBeginStack
.back()) {
4254 bool isLoad
; int depth
, effects
;
4255 int interf
= checkAnyInterf(e
, p
, isLoad
, depth
, effects
);
4256 if (interf
== InterfAccess
||
4257 interf
== SameAccess
) {
4258 p
->setLocalExprAltered();