Implement full-fidelity parsing for unknown shape fields
[hiphop-php.git] / hphp / hhbbc / cfg.cpp
blobbf2341273c820645d6154c9e0e96604e6f6b311e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 +----------------------------------------------------------------------+
16 #include "hphp/hhbbc/cfg.h"
18 #include <boost/dynamic_bitset.hpp>
19 #include <algorithm>
20 #include <vector>
22 namespace HPHP { namespace HHBBC {
24 //////////////////////////////////////////////////////////////////////
26 namespace {
28 void postorderWalk(const php::Func& func,
29 std::vector<borrowed_ptr<php::Block>>& out,
30 boost::dynamic_bitset<>& visited,
31 php::Block& blk) {
32 if (visited[blk.id]) return;
33 visited[blk.id] = true;
34 forEachSuccessor(blk, [&] (BlockId next) {
35 postorderWalk(func, out, visited, *func.blocks[next]);
36 });
37 out.push_back(&blk);
42 //////////////////////////////////////////////////////////////////////
44 std::vector<borrowed_ptr<php::Block>> rpoSortFromMain(const php::Func& func) {
45 boost::dynamic_bitset<> visited(func.blocks.size());
46 std::vector<borrowed_ptr<php::Block>> ret;
47 ret.reserve(func.blocks.size());
48 postorderWalk(func, ret, visited, *func.blocks[func.mainEntry]);
49 std::reverse(begin(ret), end(ret));
50 return ret;
53 std::vector<borrowed_ptr<php::Block>> rpoSortAddDVs(const php::Func& func) {
54 boost::dynamic_bitset<> visited(func.blocks.size());
55 std::vector<borrowed_ptr<php::Block>> ret;
56 ret.reserve(func.blocks.size());
57 postorderWalk(func, ret, visited, *func.blocks[func.mainEntry]);
60 * We've already marked the blocks reachable from the main entry
61 * point. Do post order walks from each DV entry with the same
62 * visited set (so we'll stop if they chain to the main entry, which
63 * is the normal case).
65 for (auto it = func.params.end(); it != func.params.begin(); ) {
66 --it;
67 if (it->dvEntryPoint == NoBlockId) continue;
68 postorderWalk(func, ret, visited, *func.blocks[it->dvEntryPoint]);
70 std::reverse(begin(ret), end(ret));
71 return ret;
74 BlockToBlocks
75 computeNormalPreds(const std::vector<borrowed_ptr<php::Block>>& rpoBlocks) {
76 auto preds = BlockToBlocks{};
77 preds.reserve(rpoBlocks.size());
78 for (auto& b : rpoBlocks) {
79 if (preds.size() < b->id + 1) {
80 preds.resize(b->id + 1);
82 forEachNormalSuccessor(*b, [&] (BlockId blkId) {
83 if (preds.size() < blkId + 1) {
84 preds.resize(blkId + 1);
86 preds[blkId].insert(b);
87 });
89 return preds;
92 BlockToBlocks
93 computeFactoredPreds(const std::vector<borrowed_ptr<php::Block>>& rpoBlocks) {
94 auto preds = BlockToBlocks{};
95 preds.reserve(rpoBlocks.size());
96 for (auto& b : rpoBlocks) {
97 if (preds.size() < b->id + 1) {
98 preds.resize(b->id + 1);
100 for (auto& ex : b->factoredExits) {
101 if (preds.size() < ex + 1) {
102 preds.resize(ex + 1);
104 preds[ex].insert(b);
107 return preds;
111 * Walk forward through no-op blocks. To avoid cycles we don't take
112 * "backward" branches unless its to the lowest numbered block seen to
113 * date (this is just a heuristic to avoid having to keep a seen set,
114 * because we don't expect long cyclic chains of no-op blocks).
116 BlockId next_real_block(const php::Func& func, BlockId id) {
117 auto blk = borrow(func.blocks[id]);
118 auto min = id;
119 while (is_single_nop(*blk)) {
120 if (blk->fallthrough == id || blk->fallthrough == NoBlockId) break;
121 if (blk->fallthrough < id) {
122 if (blk->fallthrough >= min) {
123 // we may be in a cycle, but take one more hop anyway,
124 // in case we're not.
125 id = blk->fallthrough;
126 break;
128 min = blk->fallthrough;
130 id = blk->fallthrough;
131 blk = borrow(func.blocks[id]);
133 return id;
136 //////////////////////////////////////////////////////////////////////