30 {
31 const auto& block_result = am.getResult<BlockAnalysisPass>();
32 const auto& cfg_blocks = block_result.cfg_blocks;
33
34 int expected_final_depth = am.getExpectedFinalDepth();
35
37 result.stack_depth_in.assign(cfg_blocks.size(), -1);
38
39 std::vector<int> worklist;
40
41 if (!cfg_blocks.empty()) {
42 result.stack_depth_in[0] = 0;
43 worklist.push_back(0);
44 }
45
46 size_t processed_count = 0;
47 while (!worklist.empty()) {
48 processed_count++;
49 if (processed_count >
50 cfg_blocks.size() * cfg_blocks.size()) {
51 throw AnalysisError(std::format(
52 "Failed to prove stack safety; check loops. "
53 "processed_count = {}, cfg_blocks = {}, heuristic_limit = {}, "
54 "worklist_size = {}, next_block_candidate = {}",
55 processed_count, cfg_blocks.size(),
56 cfg_blocks.size() * cfg_blocks.size(), worklist.size(),
57 worklist.back()));
58 }
59
60 int block_idx = worklist.back();
61 worklist.pop_back();
62
63 const auto& block = cfg_blocks[block_idx];
64 int depth_in = result.stack_depth_in[block_idx];
65
66 if (depth_in < block.min_stack_needed) {
67 throw AnalysisError(
68 std::format("Stack underflow before executing block {}: "
69 "depth_in = {}, min_needed = {}, start token '{}'",
70 block_idx, depth_in, block.min_stack_needed,
71 tokens[block.start_token_idx].text),
72 block.start_token_idx);
73 }
74
75 int depth_out = depth_in + block.stack_effect;
76
77 for (int succ_idx : block.successors) {
78 if (result.stack_depth_in[succ_idx] == -1) {
79 result.stack_depth_in[succ_idx] = depth_out;
80 worklist.push_back(succ_idx);
81 } else if (result.stack_depth_in[succ_idx] != depth_out) {
82 throw AnalysisError(
83 std::format(
84 "Stack depth mismatch on converging paths: "
85 "block {} -> successor {}. "
86 "incoming depth = {}, recorded successor depth = {}, "
87 "current start token '{}', successor start token '{}'",
88 block_idx, succ_idx, depth_out,
89 result.stack_depth_in[succ_idx],
90 tokens[block.start_token_idx].text,
91 tokens[cfg_blocks[succ_idx].start_token_idx].text),
92 cfg_blocks[succ_idx].start_token_idx);
93 }
94 }
95 }
96
97 for (size_t i = 0; i < cfg_blocks.size(); ++i) {
98 if (result.stack_depth_in[i] != -1 &&
99 cfg_blocks[i].successors.empty()) {
100 int final_depth =
101 result.stack_depth_in[i] + cfg_blocks[i].stack_effect;
102 if (final_depth != expected_final_depth) {
103 throw AnalysisError(
104 std::format(
105 "Expression stack not balanced on "
106 "reachable terminal block {}: "
107 "final depth = {}, expected = {}, start token '{}'",
108 i, final_depth, expected_final_depth,
109 tokens[cfg_blocks[i].start_token_idx].text),
110 cfg_blocks[i].start_token_idx);
111 }
112 }
113 }
114
115 return result;
116}