Skip to content

Commit

Permalink
Add segmented stack space to ExecutionContext
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Apr 12, 2021
1 parent 5b99b52 commit 4594b99
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
10 changes: 7 additions & 3 deletions lib/fizzy/execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ ExecutionResult execute(
return Trap;

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

assert(instance.module->imported_function_types.size() == instance.imported_functions.size());
if (func_idx < instance.imported_functions.size())
Expand All @@ -573,10 +574,13 @@ ExecutionResult execute(
const auto& code = instance.module->get_code(func_idx);
auto* const memory = instance.memory.get();

const auto local_ctx = ctx.create_local_context();
const auto required_stack_space =
args_count + code.local_count + static_cast<size_t>(code.max_stack_height);

OperandStack stack(args, func_type.inputs.size(), code.local_count,
static_cast<size_t>(code.max_stack_height));
const auto local_ctx = ctx.create_local_context(required_stack_space);

OperandStack stack(
args, args_count, code.local_count, static_cast<size_t>(code.max_stack_height));

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

Expand Down
57 changes: 53 additions & 4 deletions lib/fizzy/execution_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,87 @@

#pragma once

#include "value.hpp"
#include <cassert>
#include <cstddef>

namespace fizzy
{
/// The storage for information shared by calls in the same execution "thread".
/// Users may decide how to allocate the execution context, but some good defaults are available.
class ExecutionContext
{
/// Call local execution context.
static constexpr size_t DefaultStackSpaceSegmentSize = 100;

/// Call depth increment guard.
/// It will automatically decrement the call depth to the original value
/// when going out of scope.
class [[nodiscard]] LocalContext
{
ExecutionContext& m_shared_ctx; ///< Reference to the shared execution context.

public:
Value* stack_space = nullptr;
Value* prev_stack_space_segment = nullptr;
size_t prev_free_stack_space = 0;

LocalContext(const LocalContext&) = delete;
LocalContext(LocalContext&&) = delete;
LocalContext& operator=(const LocalContext&) = delete;
LocalContext& operator=(LocalContext&&) = delete;

explicit LocalContext(ExecutionContext& ctx) noexcept : m_shared_ctx{ctx}
LocalContext(ExecutionContext& ctx, size_t required_stack_space) : m_shared_ctx{ctx}
{
++m_shared_ctx.depth;

prev_free_stack_space = m_shared_ctx.free_stack_space;

if (required_stack_space <= m_shared_ctx.free_stack_space)
{
// Must be a segment of default size or required_stack_space is 0.
const auto offset =
DefaultStackSpaceSegmentSize - m_shared_ctx.free_stack_space;
stack_space = m_shared_ctx.stack_space_segment + offset;
prev_free_stack_space = m_shared_ctx.free_stack_space;
m_shared_ctx.free_stack_space -= required_stack_space;
}
else
{
prev_stack_space_segment = m_shared_ctx.stack_space_segment;
const auto new_segment_size =
std::max(DefaultStackSpaceSegmentSize, required_stack_space);
m_shared_ctx.stack_space_segment = new Value[new_segment_size];
stack_space = m_shared_ctx.stack_space_segment;
m_shared_ctx.free_stack_space = new_segment_size - required_stack_space;
}
}

~LocalContext() noexcept { --m_shared_ctx.depth; }
~LocalContext() noexcept
{
--m_shared_ctx.depth;

m_shared_ctx.free_stack_space = prev_free_stack_space;
if (prev_stack_space_segment != nullptr)
{
assert(m_shared_ctx.stack_space_segment == stack_space);
delete[] stack_space;
m_shared_ctx.stack_space_segment = prev_stack_space_segment;
}
}
};

public:
Value first_stack_space_segment[DefaultStackSpaceSegmentSize];
Value* stack_space_segment = first_stack_space_segment;
size_t free_stack_space = DefaultStackSpaceSegmentSize;

int depth = 0; ///< Current call depth.

/// Increments the call depth and returns the local call context which
/// decrements the call depth back to the original value when going out of scope.
LocalContext create_local_context() noexcept { return LocalContext{*this}; }
LocalContext create_local_context(size_t required_stack_space = 0)
{
return LocalContext{*this, required_stack_space};
}
};
} // namespace fizzy

0 comments on commit 4594b99

Please sign in to comment.