2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
20 #include <boost/variant/static_visitor.hpp>
21 #include <boost/container/flat_set.hpp>
23 #include "hphp/hhbbc/bc.h"
24 #include "hphp/hhbbc/misc.h"
25 #include "hphp/hhbbc/representation.h"
27 namespace HPHP
{ namespace HHBBC
{
29 //////////////////////////////////////////////////////////////////////
34 void visitExnLeaves(const php::Func
& func
, const php::ExnNode
& n
, Fun f
) {
35 if (n
.idx
== NoExnNodeId
) return;
36 for (auto& c
: n
.children
) visitExnLeaves(func
, func
.exnNodes
[c
], f
);
42 //////////////////////////////////////////////////////////////////////
45 * Returns whether a block consists of a single Nop instruction.
47 inline bool is_single_nop(const php::Block
& b
) {
48 return b
.hhbcs
.size() == 1 && b
.hhbcs
.back().op
== Op::Nop
;
52 * Returns whether a block consists of a single Throw instruction.
54 inline bool is_single_throw(const php::Block
& b
) {
55 return b
.hhbcs
.size() == 1 && b
.hhbcs
.back().op
== Op::Throw
;
59 * Walk through single_nop blocks to the next block that actually does
62 BlockId
next_real_block(const php::WideFunc
& func
, BlockId id
);
65 * Walk through catch blocks, stopping at the first block which does
66 * something other than just immediately throw.
68 std::pair
<BlockId
, ExnNodeId
>
69 next_catch_block(const php::WideFunc
& func
, BlockId id
, ExnNodeId exnId
);
72 * Call a function for every jump target of a given bytecode, or Op.
73 * If the bytecode has no targets, the function is not called.
75 template<typename Bc
, class Fun
>
76 void forEachTakenEdge(Bc
& b
, Fun f
) {
81 * Call a function for every successor of `block'.
83 * Order unspecified, and the types of successor edges are not
86 * Exit edges are traversed only if the block consists of
87 * more than a single Nop instruction.
90 void forEachSuccessor(const php::Block
& block
, Fun f
) {
91 if (!is_single_nop(block
)) {
92 forEachTakenEdge(block
.hhbcs
.back(), f
);
93 if (block
.throwExit
!= NoBlockId
) f(block
.throwExit
);
95 if (block
.fallthrough
!= NoBlockId
) f(block
.fallthrough
);
99 * Call a function for every successor of `block' that is reachable
100 * through a fallthrough or taken edge.
102 template<class Block
, class Fun
>
103 void forEachNormalSuccessor(Block
& block
, Fun f
) {
104 forEachTakenEdge(block
.hhbcs
.back(), f
);
105 if (block
.fallthrough
!= NoBlockId
) f(block
.fallthrough
);
109 * Call a function for every successor of `block' that is reachable
110 * through a non-throw edge.
113 void forEachNonThrowSuccessor(const php::Block
& block
, Fun f
) {
114 forEachTakenEdge(block
.hhbcs
.back(), f
);
115 if (block
.fallthrough
!= NoBlockId
) f(block
.fallthrough
);
119 * Obtain the blocks for a function in a reverse post order, starting
120 * with the specified block. The exact order is not specified.
122 std::vector
<BlockId
> rpoSortFromBlock(const php::WideFunc
&, BlockId
);
125 * Obtain the blocks for a function in a reverse post order, starting
126 * with the main entry point. The exact order is not specified.
128 * DV initializer blocks will not appear in this list.
130 std::vector
<BlockId
> rpoSortFromMain(const php::WideFunc
&);
133 * Obtain the blocks for a function in a reverse post order, taking
134 * into account all entry points.
136 * This can be thought of as an RPO on the CFG of Func starting from a
137 * virtual empty "entry" block, with edges to each DV entry point and
138 * an edge to the main entry point.
140 std::vector
<BlockId
> rpoSortAddDVs(const php::WideFunc
&);
143 * Mappings from blocks to sets of blocks.
145 * The first level is indexed by block id. The second is a set of
148 using BlockToBlocks
= std::vector
<
149 boost::container::flat_set
<BlockId
>
153 * Find the immediate non-throw predecessors for each block in
154 * an RPO-sorted list of blocks.
156 * The BlockToBlocks map returned will have any entry for each block
157 * in the input array, but may not have entries for blocks that aren't
161 computeNonThrowPreds(const php::WideFunc
&, const std::vector
<BlockId
>&);
164 * Find the immediate throw predecessors for each block in an
165 * RPO-sorted list of blocks.
167 * The BlockToBlocks map returned will have any entry for each block
168 * in the input array, but may not have entries for blocks that aren't
172 computeThrowPreds(const php::WideFunc
&, const std::vector
<BlockId
>&);
175 * Visit each leaf in the ExnNode tree.
178 void visitExnLeaves(const php::Func
& func
, Fun f
) {
179 for (auto& n
: func
.exnNodes
) {
180 detail::visitExnLeaves(func
, n
, f
);
184 //////////////////////////////////////////////////////////////////////