@@ -45,6 +45,8 @@ constexpr ExecutionResult Trap{false};
4545// / Users may decide how to allocate the execution context, but some good defaults are available.
4646class 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
6083public:
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