Skip to content

Commit

Permalink
Make the Node a lightweight type holding pointers rather than the var…
Browse files Browse the repository at this point in the history
…iant
  • Loading branch information
ZehMatt committed Sep 4, 2024
1 parent 4e5d190 commit b3504c9
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 20 deletions.
4 changes: 2 additions & 2 deletions tests/src/tests/tests.assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ namespace zasm::tests
Program program(MachineMode::AMD64);

x86::Assembler assembler(program);

ASSERT_EQ(assembler.mov(x86::rax, x86::rax), ErrorCode::None);
auto* nodeA = assembler.getCursor();
ASSERT_EQ(assembler.mov(x86::rdx, x86::rdx), ErrorCode::None);
auto* nodeB = assembler.getCursor();
ASSERT_EQ(assembler.mov(x86::rbx, x86::rbx), ErrorCode::None);
auto* nodeC = assembler.getCursor();

program.destroy(nodeC);
ASSERT_EQ(assembler.getCursor(), nodeB);

Expand Down
51 changes: 39 additions & 12 deletions zasm/include/zasm/program/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ namespace zasm
};
ZASM_ENABLE_ENUM_OPERATORS(NodeFlags);

template<typename T> constexpr std::size_t TypeHash()
{
std::size_t result{ 14695981039346656037 };

#ifdef _MSC_VER
# define F __FUNCSIG__
#else
# define F __PRETTY_FUNCTION__
#endif

for (const auto& c : F)
{
result ^= c;
result *= 1099511628211;
}

return result;
}

template<typename T> constexpr std::size_t constexpr_hash = TypeHash<std::decay_t<T>>();

/// <summary>
/// A type to hold data such as Instruction, Label, Data etc. within a doubly
/// linked list managed by the Program. The data is internally stored as a variant
Expand All @@ -40,7 +61,7 @@ namespace zasm
NodeFlags _flags{};
Node* _prev{};
Node* _next{};
std::variant<Sentinel, Instruction, Label, EmbeddedLabel, Data, Section, Align> _data{};
std::variant<Sentinel*, Instruction*, Label*, EmbeddedLabel*, Data*, Section*, Align*> _data2{};

union
{
Expand All @@ -51,9 +72,9 @@ namespace zasm
protected:
// Internal use only.
template<typename T>
constexpr Node(Id nodeId, T&& val) noexcept
constexpr Node(Id nodeId, T* val) noexcept
: _id{ nodeId }
, _data{ std::forward<T>(val) }
, _data2{ val }
{
}

Expand Down Expand Up @@ -97,7 +118,7 @@ namespace zasm
/// <returns>True if the T is the current type</returns>
template<typename T> constexpr bool holds() const noexcept
{
return std::holds_alternative<T>(_data);
return std::holds_alternative<T*>(_data2);
}

/// <summary>
Expand All @@ -108,13 +129,13 @@ namespace zasm
/// <returns>Returns a reference to the data with the type of T</returns>
template<typename T> constexpr const T& get() const
{
return std::get<T>(_data);
return *std::get<T*>(_data2);
}

/// <see cref="get"/>
template<typename T> constexpr T& get()
{
return std::get<T>(_data);
return *std::get<T*>(_data2);
}

/// <summary>
Expand All @@ -125,13 +146,19 @@ namespace zasm
/// <returns>Pointer of type T</returns>
template<typename T> constexpr const T* getIf() const noexcept
{
return std::get_if<T>(&_data);
auto r = std::get_if<T*>(&_data2);
if (r == nullptr)
return nullptr;
return *r;
}

/// <see cref="getIf"/>
template<typename T> constexpr T* getIf() noexcept
{
return std::get_if<T>(&_data);
auto r = std::get_if<T*>(&_data2);
if (r == nullptr)
return nullptr;
return *r;
}

/// <summary>
Expand All @@ -141,15 +168,15 @@ namespace zasm
/// <typeparam name="F">Function type</typeparam>
/// <param name="func">Visitor function</param>
/// <returns>The result of the visitor function</returns>
template<typename F> constexpr auto visit(F&& func) const
template<typename TPred> constexpr auto visit(TPred&& func) const
{
return std::visit(std::forward<F>(func), _data);
return std::visit([&](auto&& obj) { return func(*obj); }, _data2);
}

/// <see cref="visit"/>
template<typename F> constexpr auto visit(F&& func)
template<typename TPred> constexpr auto visit(TPred&& func)
{
return std::visit(std::forward<F>(func), _data);
return std::visit([&](auto&& obj) { return func(*obj); }, _data2);
}

/// <summary>
Expand Down
28 changes: 24 additions & 4 deletions zasm/src/zasm/src/program/program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ namespace zasm
return entry.node;
}

template<bool TNotify, typename F, typename... TArgs>
static void notifyObservers(const F&& func, const std::vector<Observer*>& observers, TArgs&&... args) noexcept
template<bool TNotify, typename TPred, typename... TArgs>
static void notifyObservers(const TPred&& func, const std::vector<Observer*>& observers, TArgs&&... args) noexcept
{
if constexpr (TNotify)
{
Expand Down Expand Up @@ -374,6 +374,20 @@ namespace zasm

// Release.
auto* nodeToDestroy = detail::toInternal(node);

node->visit([&](auto& ptr) {

using T = std::decay_t<decltype(ptr)>;

auto& objectPool = state.nodePools.getPool<T>();
objectPool.destroy(&ptr);

if (!quickDestroy)
{
objectPool.deallocate(&ptr, 1);
}
});

state.nodePool.destroy(nodeToDestroy);

if (!quickDestroy)
Expand Down Expand Up @@ -437,7 +451,7 @@ namespace zasm
return _state->entryPoint;
}

template<typename... TArgs> Node* createNode_(detail::ProgramState& state, TArgs&&... args)
template<typename T> Node* createNode_(detail::ProgramState& state, T&& object)
{
const auto nextId = state.nextNodeId;
state.nextNodeId = static_cast<Node::Id>(static_cast<std::underlying_type_t<Node::Id>>(nextId) + 1U);
Expand All @@ -449,7 +463,13 @@ namespace zasm
return nullptr;
}

::new ((void*)node) detail::Node(nextId, std::forward<TArgs&&>(args)...);
using ObjectType = std::decay_t<T>;
auto& objectPool = state.nodePools.getPool<ObjectType>();

auto* obj = objectPool.allocate(1);
::new ((void*)obj) ObjectType(std::move(object));

::new ((void*)node) detail::Node(nextId, obj);

notifyObservers<true>(&Observer::onNodeCreated, state.observer, node);

Expand Down
4 changes: 2 additions & 2 deletions zasm/src/zasm/src/program/program.node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ namespace zasm
{
public:
template<typename T>
constexpr Node(zasm::Node::Id id, T&& val) noexcept
: ::zasm::Node(id, std::forward<T>(val))
constexpr Node(zasm::Node::Id id, T* val) noexcept
: ::zasm::Node(id, val)
{
}
void setPrev(::zasm::Node* node) noexcept
Expand Down
15 changes: 15 additions & 0 deletions zasm/src/zasm/src/program/program.state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <Zydis/Zydis.h>
#include <cstddef>
#include <tuple>
#include <vector>
#include <zasm/base/label.hpp>
#include <zasm/base/mode.hpp>
Expand Down Expand Up @@ -46,10 +47,24 @@ namespace zasm::detail
zasm::Node* node{};
};

template<typename... TTypes> struct ObjectPools
{
std::tuple<ObjectPool<TTypes, PoolSize>...> pools;

template<typename T> auto& getPool()
{
return std::get<ObjectPool<T, PoolSize>>(pools);
}
};

using NodePools = ObjectPools<Sentinel, Instruction, Label, EmbeddedLabel, Data, Section, Align>;

struct NodeStorage
{
ObjectPool<Node, PoolSize> nodePool;
Node::Id nextNodeId{};

NodePools nodePools;
};

struct NodeList
Expand Down

0 comments on commit b3504c9

Please sign in to comment.