Skip to content

Commit 83be14a

Browse files
committed
Remove frame.stack_height
1 parent 867b082 commit 83be14a

1 file changed

Lines changed: 55 additions & 67 deletions

File tree

lib/fizzy/parser_expr.cpp

Lines changed: 55 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,8 @@ struct ControlFrame
4545
size_t immediates_offset{0};
4646

4747
/// The frame stack height of the parent frame.
48-
/// TODO: Storing this is not strictly required, as the parent frame is available
49-
/// in the control_stack.
5048
const int parent_stack_height{0};
5149

52-
/// The frame stack height.
53-
int stack_height{0};
54-
5550
/// Whether the remainder of the block is unreachable (used to handle stack-polymorphic typing
5651
/// after branches).
5752
bool unreachable{false};
@@ -65,8 +60,7 @@ struct ControlFrame
6560
type{_type},
6661
code_offset{_code_offset},
6762
immediates_offset{_immediates_offset},
68-
parent_stack_height{_parent_stack_height},
69-
stack_height{_parent_stack_height}
63+
parent_stack_height{_parent_stack_height}
7064
{}
7165
};
7266

@@ -93,23 +87,12 @@ void update_operand_stack(ControlFrame& frame, Stack<ValType>& operand_stack,
9387
span<const ValType> inputs, span<const ValType> outputs)
9488
{
9589
const auto inputs_size = static_cast<int>(inputs.size());
96-
const auto outputs_size = static_cast<int>(outputs.size());
9790

98-
// Update frame.stack_height.
99-
if (frame.stack_height < frame.parent_stack_height + inputs_size)
100-
{
101-
// Stack is polymorphic after unreachable instruction: underflow is ignored,
102-
// but we need to count stack growth to detect extra values at the end of the block.
103-
if (frame.unreachable)
104-
{
105-
// Add instruction's/call's output values only.
106-
frame.stack_height = frame.parent_stack_height + outputs_size;
107-
}
108-
else
109-
throw validation_error{"stack underflow"};
110-
}
111-
else
112-
frame.stack_height += outputs_size - inputs_size;
91+
// Stack is polymorphic after unreachable instruction: underflow is ignored,
92+
// but we need to count stack growth to detect extra values at the end of the block.
93+
if (!frame.unreachable &&
94+
static_cast<int>(operand_stack.size()) < frame.parent_stack_height + inputs_size)
95+
throw validation_error{"stack underflow"};
11396

11497
// Update operand_stack.
11598
for (auto it = inputs.begin() + inputs.size(); it != inputs.begin(); --it)
@@ -135,20 +118,22 @@ inline void update_caller_frame(
135118
update_operand_stack(frame, operand_stack, func_type.inputs, func_type.outputs);
136119
}
137120

138-
void validate_result_count(const ControlFrame& frame)
121+
void validate_result_count(const ControlFrame& frame, const Stack<ValType>& operand_stack)
139122
{
123+
const auto frame_stack_height = static_cast<int>(operand_stack.size());
124+
140125
// This is checked by "stack underflow".
141-
assert(frame.stack_height >= frame.parent_stack_height);
126+
assert(frame_stack_height >= frame.parent_stack_height);
142127

143128
const auto arity = frame.type.has_value() ? 1 : 0;
144129

145-
if (frame.stack_height > frame.parent_stack_height + arity)
130+
if (frame_stack_height > frame.parent_stack_height + arity)
146131
throw validation_error{"too many results"};
147132

148133
if (frame.unreachable)
149134
return;
150135

151-
if (frame.stack_height < frame.parent_stack_height + arity)
136+
if (frame_stack_height < frame.parent_stack_height + arity)
152137
throw validation_error{"missing result"};
153138
}
154139

@@ -161,14 +146,16 @@ inline uint8_t get_branch_arity(const ControlFrame& frame) noexcept
161146
return frame.instruction == Instr::loop ? 0 : arity;
162147
}
163148

164-
inline void validate_branch_stack_height(
165-
const ControlFrame& current_frame, const ControlFrame& branch_frame)
149+
inline void validate_branch_stack_height(const ControlFrame& current_frame,
150+
const ControlFrame& branch_frame, const Stack<ValType>& operand_stack)
166151
{
167-
assert(current_frame.stack_height >= current_frame.parent_stack_height);
152+
const auto current_frame_stack_height = static_cast<int>(operand_stack.size());
153+
154+
assert(current_frame_stack_height >= current_frame.parent_stack_height);
168155

169156
const auto arity = get_branch_arity(branch_frame);
170157
if (!current_frame.unreachable &&
171-
(current_frame.stack_height < current_frame.parent_stack_height + arity))
158+
(current_frame_stack_height < current_frame.parent_stack_height + arity))
172159
throw validation_error{"branch stack underflow"};
173160
}
174161

@@ -190,22 +177,18 @@ void push_branch_immediates(
190177
push(immediates, arity);
191178
}
192179

193-
inline void mark_frame_unreachable(ControlFrame& frame) noexcept
180+
inline void mark_frame_unreachable(ControlFrame& frame, Stack<ValType>& operand_stack) noexcept
194181
{
195182
frame.unreachable = true;
196-
frame.stack_height = frame.parent_stack_height;
183+
operand_stack.shrink(static_cast<size_t>(frame.parent_stack_height));
197184
}
198185

199186
inline void drop_operand(
200187
ControlFrame& frame, Stack<ValType>& operand_stack, std::optional<ValType> expected_type)
201188
{
202-
if (frame.stack_height < frame.parent_stack_height + 1)
203-
{
204-
if (!frame.unreachable)
205-
throw validation_error{"stack underflow"};
206-
}
207-
else
208-
--frame.stack_height;
189+
if (static_cast<int>(operand_stack.size()) < frame.parent_stack_height + 1 &&
190+
!frame.unreachable)
191+
throw validation_error{"stack underflow"};
209192

210193
const auto actual_type =
211194
(frame.unreachable &&
@@ -216,9 +199,8 @@ inline void drop_operand(
216199
throw validation_error{"type mismatch"};
217200
}
218201

219-
inline void push_operand(ControlFrame& frame, Stack<ValType>& operand_stack, ValType type)
202+
inline void push_operand(Stack<ValType>& operand_stack, ValType type)
220203
{
221-
++frame.stack_height;
222204
operand_stack.push(type);
223205
}
224206

@@ -282,7 +264,8 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
282264
// already popped/reset), but it does not matter, as these instructions do not modify
283265
// stack height anyway.
284266
if (!frame.unreachable)
285-
code.max_stack_height = std::max(code.max_stack_height, frame.stack_height);
267+
code.max_stack_height =
268+
std::max(code.max_stack_height, static_cast<int>(operand_stack.size()));
286269

287270
update_operand_stack(frame, operand_stack, types.inputs, types.outputs);
288271

@@ -375,7 +358,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
375358
break;
376359

377360
case Instr::unreachable:
378-
mark_frame_unreachable(frame);
361+
mark_frame_unreachable(frame, operand_stack);
379362
break;
380363

381364
case Instr::drop:
@@ -454,8 +437,8 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
454437
std::tie(type, pos) = parse_blocktype(pos, end);
455438

456439
// Push label with immediates offset after arity.
457-
control_stack.emplace(Instr::block, type, frame.stack_height, code.instructions.size(),
458-
code.immediates.size());
440+
control_stack.emplace(Instr::block, type, static_cast<int>(operand_stack.size()),
441+
code.instructions.size(), code.immediates.size());
459442
break;
460443
}
461444

@@ -464,8 +447,8 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
464447
std::optional<ValType> type;
465448
std::tie(type, pos) = parse_blocktype(pos, end);
466449

467-
control_stack.emplace(Instr::loop, type, frame.stack_height, code.instructions.size(),
468-
code.immediates.size());
450+
control_stack.emplace(Instr::loop, type, static_cast<int>(operand_stack.size()),
451+
code.instructions.size(), code.immediates.size());
469452

470453
break;
471454
}
@@ -475,8 +458,8 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
475458
std::optional<ValType> type;
476459
std::tie(type, pos) = parse_blocktype(pos, end);
477460

478-
control_stack.emplace(Instr::if_, type, frame.stack_height, code.instructions.size(),
479-
code.immediates.size());
461+
control_stack.emplace(Instr::if_, type, static_cast<int>(operand_stack.size()),
462+
code.instructions.size(), code.immediates.size());
480463

481464
// Placeholders for immediate values, filled at the matching end or else instructions.
482465
push(code.immediates, uint32_t{0}); // Diff to the else instruction
@@ -490,10 +473,9 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
490473
if (frame.instruction != Instr::if_)
491474
throw parser_error{"unexpected else instruction (if instruction missing)"};
492475

493-
validate_result_count(frame); // else is the end of if.
476+
validate_result_count(frame, operand_stack); // else is the end of if.
494477

495478
// Reset frame after if. The if result type validation not implemented yet.
496-
frame.stack_height = frame.parent_stack_height;
497479
frame.unreachable = false;
498480
const auto if_imm_offset = frame.immediates_offset;
499481
frame.immediates_offset = code.immediates.size();
@@ -518,7 +500,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
518500

519501
case Instr::end:
520502
{
521-
validate_result_count(frame);
503+
validate_result_count(frame, operand_stack);
522504

523505
if (frame.instruction != Instr::loop) // If end of block/if/else instruction.
524506
{
@@ -553,11 +535,13 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
553535
}
554536
const auto type = frame.type;
555537
control_stack.pop(); // Pop the current frame.
538+
operand_stack.shrink(static_cast<size_t>(std::max(0, frame.parent_stack_height)));
539+
//operand_stack.shrink(static_cast<size_t>(frame.parent_stack_height));
556540

557541
if (control_stack.empty())
558542
continue_parsing = false;
559543
else if (type.has_value())
560-
control_stack.top().stack_height += 1; // The results of the popped frame.
544+
operand_stack.push(*type);
561545
break;
562546
}
563547

@@ -572,15 +556,16 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
572556

573557
auto& branch_frame = control_stack[label_idx];
574558

575-
validate_branch_stack_height(frame, branch_frame);
559+
validate_branch_stack_height(frame, branch_frame, operand_stack);
576560

577561
// Remember this br immediates offset to fill it at end instruction.
578562
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
579563

580-
push_branch_immediates(branch_frame, frame.stack_height, code.immediates);
564+
push_branch_immediates(
565+
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
581566

582567
if (instr == Instr::br)
583-
mark_frame_unreachable(frame);
568+
mark_frame_unreachable(frame, operand_stack);
584569

585570
break;
586571
}
@@ -604,7 +589,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
604589
auto& default_branch_frame = control_stack[default_label_idx];
605590
const auto default_branch_arity = get_branch_arity(default_branch_frame);
606591

607-
validate_branch_stack_height(frame, default_branch_frame);
592+
validate_branch_stack_height(frame, default_branch_frame, operand_stack);
608593

609594
// Remember immediates offset for all br items to fill them at end instruction.
610595
push(code.immediates, static_cast<uint32_t>(label_indices.size()));
@@ -616,13 +601,15 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
616601
throw validation_error{"br_table labels have inconsistent types"};
617602

618603
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
619-
push_branch_immediates(branch_frame, frame.stack_height, code.immediates);
604+
push_branch_immediates(
605+
branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
620606
}
621607

622608
default_branch_frame.br_immediate_offsets.push_back(code.immediates.size());
623-
push_branch_immediates(default_branch_frame, frame.stack_height, code.immediates);
609+
push_branch_immediates(
610+
default_branch_frame, static_cast<int>(operand_stack.size()), code.immediates);
624611

625-
mark_frame_unreachable(frame);
612+
mark_frame_unreachable(frame, operand_stack);
626613

627614
break;
628615
}
@@ -635,13 +622,14 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
635622

636623
auto& branch_frame = control_stack[label_idx];
637624

638-
validate_branch_stack_height(frame, branch_frame);
625+
validate_branch_stack_height(frame, branch_frame, operand_stack);
639626

640627
branch_frame.br_immediate_offsets.push_back(code.immediates.size());
641628

642-
push_branch_immediates(control_stack[label_idx], frame.stack_height, code.immediates);
629+
push_branch_immediates(
630+
control_stack[label_idx], static_cast<int>(operand_stack.size()), code.immediates);
643631

644-
mark_frame_unreachable(frame);
632+
mark_frame_unreachable(frame, operand_stack);
645633
break;
646634
}
647635

@@ -688,7 +676,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
688676
uint32_t local_idx;
689677
std::tie(local_idx, pos) = leb128u_decode<uint32_t>(pos, end);
690678

691-
push_operand(frame, operand_stack, find_local_type(func_inputs, locals, local_idx));
679+
push_operand(operand_stack, find_local_type(func_inputs, locals, local_idx));
692680

693681
push(code.immediates, local_idx);
694682
break;
@@ -710,7 +698,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
710698

711699
const auto type = find_local_type(func_inputs, locals, local_idx);
712700
drop_operand(frame, operand_stack, type);
713-
push_operand(frame, operand_stack, type);
701+
push_operand(operand_stack, type);
714702

715703
push(code.immediates, local_idx);
716704
break;
@@ -724,7 +712,7 @@ parser_result<Code> parse_expr(const uint8_t* pos, const uint8_t* end, FuncIdx f
724712
if (global_idx >= module.get_global_count())
725713
throw validation_error{"accessing global with invalid index"};
726714

727-
push_operand(frame, operand_stack, module.get_global_type(global_idx).value_type);
715+
push_operand(operand_stack, module.get_global_type(global_idx).value_type);
728716

729717
push(code.immediates, global_idx);
730718
break;

0 commit comments

Comments
 (0)