summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp
blob: 195c46e125f92a277e09c191525958cb7d0a49b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
 * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <LibJS/Bytecode/PassManager.h>

namespace JS::Bytecode::Passes {

void PlaceBlocks::perform(PassPipelineExecutable& executable)
{
    started();

    VERIFY(executable.cfg.has_value());
    auto cfg = executable.cfg.release_value();

    Vector<BasicBlock&> replaced_blocks;
    HashTable<BasicBlock const*> reachable_blocks;

    // Visit the blocks in CFG order
    Function<void(BasicBlock const*)> visit = [&](auto* block) {
        if (reachable_blocks.contains(block))
            return;

        reachable_blocks.set(block);
        replaced_blocks.append(*const_cast<BasicBlock*>(block));

        auto children = cfg.find(block);
        if (children == cfg.end())
            return;

        for (auto& entry : children->value)
            visit(entry);
    };

    // Make sure to visit the entry block first
    visit(executable.executable.basic_blocks.first());

    for (auto& entry : cfg)
        visit(entry.key);

    // Put the unreferenced blocks back in at the end
    for (auto& entry : static_cast<Vector<NonnullOwnPtr<BasicBlock>>&>(executable.executable.basic_blocks)) {
        if (reachable_blocks.contains(entry.ptr()))
            (void)entry.leak_ptr();
        else
            replaced_blocks.append(*entry.leak_ptr()); // Don't try to do DCE here.
    }

    executable.executable.basic_blocks.clear();
    for (auto& block : replaced_blocks)
        executable.executable.basic_blocks.append(adopt_own(block));

    finished();
}

}