Skip to content

Commit 4660b69

Browse files
committed
Add segmented stack space to ExecutionContext
1 parent fa2c896 commit 4660b69

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

lib/fizzy/execute.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ ExecutionResult execute(
565565
return Trap;
566566

567567
const auto& func_type = instance.module->get_function_type(func_idx);
568+
const auto args_count = func_type.inputs.size();
568569

569570
assert(instance.module->imported_function_types.size() == instance.imported_functions.size());
570571
if (func_idx < instance.imported_functions.size())
@@ -573,10 +574,12 @@ ExecutionResult execute(
573574
const auto& code = instance.module->get_code(func_idx);
574575
auto* const memory = instance.memory.get();
575576

576-
const auto ctx_guard = ctx.increment_call_depth();
577+
const auto required_stack_space =
578+
args_count + code.local_count + static_cast<size_t>(code.max_stack_height);
579+
const auto ctx_guard = ctx.increment_call_depth(required_stack_space);
577580

578-
OperandStack stack(args, func_type.inputs.size(), code.local_count,
579-
static_cast<size_t>(code.max_stack_height));
581+
OperandStack stack(
582+
args, args_count, code.local_count, static_cast<size_t>(code.max_stack_height));
580583

581584
const uint8_t* pc = code.instructions.data();
582585

lib/fizzy/execute.hpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ constexpr ExecutionResult Trap{false};
4545
/// Users may decide how to allocate the execution context, but some good defaults are available.
4646
class ExecutionContext
4747
{
48+
static constexpr size_t DefaultStackSpaceSegmentSize = 100;
49+
4850
/// Call depth increment guard.
4951
/// It will automatically decrement the call depth to the original value
5052
/// when going out of scope.
@@ -53,19 +55,63 @@ class ExecutionContext
5355
ExecutionContext& m_execution_context; ///< Reference to the guarded execution context.
5456

5557
public:
58+
Value* stack_space = nullptr;
59+
Value* prev_stack_space_segment = nullptr;
60+
size_t prev_free_stack_space = 0;
61+
62+
Guard(Guard&&) = default;
63+
Guard(const Guard&) = delete;
64+
Guard& operator=(Guard&&) = delete;
65+
Guard& operator=(const Guard&) = delete;
66+
5667
explicit Guard(ExecutionContext& ctx) noexcept : m_execution_context{ctx} {}
57-
~Guard() noexcept { --m_execution_context.depth; }
68+
69+
~Guard() noexcept
70+
{
71+
--m_execution_context.depth;
72+
73+
m_execution_context.free_stack_space = prev_free_stack_space;
74+
if (prev_stack_space_segment != nullptr)
75+
{
76+
assert(m_execution_context.stack_space_segment == stack_space);
77+
delete[] stack_space;
78+
m_execution_context.stack_space_segment = prev_stack_space_segment;
79+
}
80+
}
5881
};
5982

6083
public:
84+
Value first_stack_space_segment[DefaultStackSpaceSegmentSize];
85+
Value* stack_space_segment = first_stack_space_segment;
86+
size_t free_stack_space = DefaultStackSpaceSegmentSize;
87+
6188
int depth = 0; ///< Current call depth.
6289

6390
/// Increments the call depth and returns the guard object which decrements
6491
/// the call depth back to the original value when going out of scope.
65-
Guard increment_call_depth() noexcept
92+
Guard increment_call_depth(size_t required_stack_space = 0) noexcept
6693
{
6794
++depth;
68-
return Guard{*this};
95+
Guard g{*this};
96+
97+
g.prev_free_stack_space = free_stack_space;
98+
99+
if (required_stack_space <= free_stack_space)
100+
{
101+
// Must be a segment of default size or required_stack_space is 0.
102+
const auto offset = DefaultStackSpaceSegmentSize - free_stack_space;
103+
g.stack_space = stack_space_segment + offset;
104+
g.prev_free_stack_space = free_stack_space;
105+
free_stack_space -= required_stack_space;
106+
return g;
107+
}
108+
109+
g.prev_stack_space_segment = stack_space_segment;
110+
const auto new_segment_size = std::max(DefaultStackSpaceSegmentSize, required_stack_space);
111+
stack_space_segment = new Value[new_segment_size];
112+
g.stack_space = stack_space_segment;
113+
free_stack_space = new_segment_size - required_stack_space;
114+
return g;
69115
}
70116
};
71117

0 commit comments

Comments
 (0)