Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
7181c15
feat: create interfaces for gc and basic reference scanners
cloalenka Jan 5, 2026
1dcdb37
feat: add reference scanning support to VirtualTable
cloalenka Jan 5, 2026
ce98cb6
feat: create MemoryManager
cloalenka Jan 5, 2026
de97b9c
feat: replace all runtime::AllocateObject calls with MemoryManager
cloalenka Jan 5, 2026
17af547
feat: add IsReferenceType method
cloalenka Jan 5, 2026
7d469a1
feat: add MemoryManager as field in PassedExecutionData
cloalenka Jan 5, 2026
53999d7
feat: add mark-and-sweep gc implementation
cloalenka Jan 5, 2026
0aa26b6
feat: change vm_ui
cloalenka Jan 5, 2026
9c7f818
Merge branch 'master' into garbage_collector
cloalenka Jan 5, 2026
92be319
refactor: move some files
cloalenka Jan 5, 2026
6451262
refactor: add reference scanners for string and file
cloalenka Jan 5, 2026
225fe9d
refactor: change Clear in vm_ui
cloalenka Jan 5, 2026
81a6f95
feat: optimize garbage collection
cloalenka Jan 5, 2026
64a1642
refactor: fix codestyle
cloalenka Jan 5, 2026
4dc2852
test: changed allocation methods
cloalenka Jan 5, 2026
43c2963
tests: fix codestyle
cloalenka Jan 5, 2026
d31307a
fix: add error handling in memory manager
cloalenka Jan 7, 2026
6b68425
fix: add include
cloalenka Jan 7, 2026
cf5b6d0
fix: improve memory management and object repository handling
bialger Jan 7, 2026
a95b9b9
fix: clean up whitespace in ObjectRepository methods
bialger Jan 7, 2026
02086e2
fix: enhance memory usage tracking with platform-specific implementat…
bialger Jan 7, 2026
28152ea
chore: update subproject commit reference in test examples
bialger Jan 7, 2026
9d0b55e
refactor: update MemoryManager to accept custom garbage collector and…
bialger Jan 7, 2026
17e529d
feat: add max-objects argument to VM console UI and update MemoryMana…
bialger Jan 7, 2026
06843be
feat: add getters to field information
cloalenka Jan 8, 2026
fec7bca
feat: change constructor and scanning logic
cloalenka Jan 8, 2026
a97f6be
fix: change gc trigger and allocation
cloalenka Jan 8, 2026
ea0f732
feat: add reference scanner setting
cloalenka Jan 8, 2026
be0acc3
feat: add memset
cloalenka Jan 8, 2026
77c6860
fix: added allocation error check
cloalenka Jan 8, 2026
a8902e7
fix: remove stack copying
cloalenka Jan 8, 2026
b28863d
fix: remove GetDataPointer usage
cloalenka Jan 8, 2026
f1f7191
fix: add nullcheck for objects in mark phase
cloalenka Jan 8, 2026
9d719a1
fix: add error logging in sweeping phase for dealloc
cloalenka Jan 8, 2026
1d707d8
fix: change unmarking objects in sweep
cloalenka Jan 8, 2026
77c7dd7
fix: change order between deallocating and removing in DeallocateObject
cloalenka Jan 8, 2026
bf3d5a0
fix: add error saving in Clear function
cloalenka Jan 8, 2026
c78816b
fix: codestyle
cloalenka Jan 8, 2026
134e565
fix: codestyle
cloalenka Jan 8, 2026
2398ad5
fix: codestyle
cloalenka Jan 8, 2026
767616c
fix: update MarkAndSweepGC to copy stack in AddRoots and improve erro…
bialger Jan 8, 2026
6773f8a
test: add MemcheckTest to validate VM execution with example data
bialger Jan 8, 2026
7e4eeed
refactor: move HashVector implementation to BuiltinFunctions.cpp and …
bialger Jan 9, 2026
738433f
refactor: simplify reference scanning in MarkAndSweepGC and introduce…
bialger Jan 9, 2026
cb3ecfd
chore: update subproject commit reference in test examples
bialger Jan 9, 2026
3a3f89a
refactor: streamline reference scanning by removing EmptyReferenceSca…
bialger Jan 9, 2026
15c3231
refactor: improve code readability by formatting constructor calls in…
bialger Jan 9, 2026
4d7a60a
fix: changed gc trigger placement
cloalenka Jan 9, 2026
9a39e49
fix: correct value retrieval in NullCoalesce function to ensure prope…
bialger Jan 10, 2026
8ef755d
tests: add unit-tests for gc
cloalenka Jan 10, 2026
32ba5b3
fix: codestyle
cloalenka Jan 10, 2026
e055261
fix: codestyle
cloalenka Jan 10, 2026
c0bf3c0
fix: add TearDown for gc tests
cloalenka Jan 10, 2026
b3179db
fix: add array destructor
cloalenka Jan 10, 2026
de2997f
fix: codestyle
cloalenka Jan 10, 2026
750c6e3
fix: initialize structures in GetMemoryUsage for better safety and cl…
bialger Jan 10, 2026
74c4775
fix: adjust structure initialization in GetMemoryUsage for consistenc…
bialger Jan 10, 2026
f472477
fix: terminal symbols handling in BytecodeParser
cloalenka Jan 10, 2026
9e2ad2f
fix: PushChar handling in parser
cloalenka Jan 10, 2026
0a1d7ee
tests: + pushchar - newarray
cloalenka Jan 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/bytecode_parser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ add_library(bytecode_parser STATIC
scenarios/VtableParser.cpp
scenarios/CommandFactory.cpp
scenarios/FunctionFactory.cpp
scenarios/PlaceholderCommandFactory.cpp
)


Expand Down
5 changes: 4 additions & 1 deletion lib/bytecode_parser/ParsingSession.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "ParsingSession.hpp"

#include <tokens/EofToken.hpp>
#include <tokens/LiteralToken.hpp>
#include <tokens/values/StringValue.hpp>

namespace ovum::bytecode::parser {

Expand Down Expand Up @@ -118,7 +120,8 @@ std::expected<std::string, BytecodeParserError> ParsingSession::ConsumeStringLit
std::to_string(token->GetPosition().GetColumn())));
}

std::string value = Current()->GetLexeme();
std::string value =
dynamic_cast<StringValue*>(dynamic_cast<ovum::LiteralToken*>(Current().get())->GetValue())->ToString();

value = value.substr(1, value.length() - 2);

Expand Down
22 changes: 20 additions & 2 deletions lib/bytecode_parser/scenarios/CommandFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

namespace ovum::bytecode::parser {

const std::unordered_set<std::string> CommandFactory::kStringCommands = {"PushString", "PushChar"};
const std::unordered_set<std::string> CommandFactory::kStringCommands = {"PushString"};
const std::unordered_set<std::string> CommandFactory::kCharCommands = {"PushChar"};

const std::unordered_set<std::string> CommandFactory::kIntegerCommands = {
"PushInt", "PushByte", "Rotate", "LoadLocal", "SetLocal", "LoadStatic", "SetStatic", "GetField", "SetField"};
Expand All @@ -16,7 +17,7 @@ const std::unordered_set<std::string> CommandFactory::kFloatCommands = {"PushFlo
const std::unordered_set<std::string> CommandFactory::kBooleanCommands = {"PushBool"};

const std::unordered_set<std::string> CommandFactory::kIdentCommands = {
"NewArray", "Call", "CallVirtual", "CallConstructor", "GetVTable", "SetVTable", "SafeCall", "IsType", "SizeOf"};
"Call", "CallVirtual", "CallConstructor", "GetVTable", "SetVTable", "SafeCall", "IsType", "SizeOf"};

std::expected<std::unique_ptr<vm::execution_tree::IExecutable>, BytecodeParserError> CommandFactory::CreateCommand(
const std::string& cmd_name, std::shared_ptr<ParsingSession> ctx) const {
Expand Down Expand Up @@ -105,6 +106,23 @@ std::expected<std::unique_ptr<vm::execution_tree::IExecutable>, BytecodeParserEr
return std::move(cmd.value());
}

if (kCharCommands.contains(cmd_name)) {
std::expected<int64_t, BytecodeParserError> value = ctx->ConsumeIntLiteral();

if (!value) {
return std::unexpected(value.error());
}

std::expected<std::unique_ptr<vm::execution_tree::IExecutable>, std::out_of_range> cmd =
vm::execution_tree::CreateIntegerCommandByName(cmd_name, value.value());

if (!cmd) {
return std::unexpected(BytecodeParserError("Failed to create char command: " + cmd_name));
}

return std::move(cmd.value());
}

std::expected<std::unique_ptr<vm::execution_tree::IExecutable>, std::out_of_range> cmd =
vm::execution_tree::CreateSimpleCommandByName(cmd_name);

Expand Down
1 change: 1 addition & 0 deletions lib/bytecode_parser/scenarios/CommandFactory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class CommandFactory : public ICommandFactory {
static const std::unordered_set<std::string> kFloatCommands;
static const std::unordered_set<std::string> kBooleanCommands;
static const std::unordered_set<std::string> kIdentCommands;
static const std::unordered_set<std::string> kCharCommands;
};

} // namespace ovum::bytecode::parser
Expand Down
79 changes: 0 additions & 79 deletions lib/bytecode_parser/scenarios/PlaceholderCommandFactory.cpp

This file was deleted.

21 changes: 0 additions & 21 deletions lib/bytecode_parser/scenarios/PlaceholderCommandFactory.hpp

This file was deleted.

92 changes: 56 additions & 36 deletions lib/execution_tree/BytecodeCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <cmath>
#include <ctime>
#include <filesystem>
#include <iostream>
#include <random>
#include <ranges>
#include <sstream>
Expand All @@ -21,8 +20,17 @@

#ifdef _WIN32
#include <windows.h>

#include <psapi.h>
#elif __APPLE__
#include <dlfcn.h>
#include <unistd.h>

#include <mach/mach.h>
#include <mach/task_info.h>
#else
#include <dlfcn.h>
#include <sys/resource.h>
#include <unistd.h>
#endif

Expand Down Expand Up @@ -109,10 +117,8 @@ std::expected<ExecutionResult, std::runtime_error> PushString(PassedExecutionDat
return std::unexpected(vtable_index_result.error());
}

auto string_obj_result = runtime::AllocateObject(*string_vtable,
static_cast<uint32_t>(vtable_index_result.value()),
data.memory.object_repository,
data.allocator);
auto string_obj_result =
data.memory_manager.AllocateObject(*string_vtable, static_cast<uint32_t>(vtable_index_result.value()), data);

if (!string_obj_result.has_value()) {
return std::unexpected(string_obj_result.error());
Expand Down Expand Up @@ -140,8 +146,8 @@ std::expected<ExecutionResult, std::runtime_error> PushNull(PassedExecutionData&
return std::unexpected(vtable_index_result.error());
}

auto null_obj_result = runtime::AllocateObject(
*null_vtable, static_cast<uint32_t>(vtable_index_result.value()), data.memory.object_repository, data.allocator);
auto null_obj_result =
data.memory_manager.AllocateObject(*null_vtable, static_cast<uint32_t>(vtable_index_result.value()), data);

if (!null_obj_result.has_value()) {
return std::unexpected(null_obj_result.error());
Expand Down Expand Up @@ -1211,8 +1217,7 @@ std::expected<ExecutionResult, std::runtime_error> CallConstructor(PassedExecuti
return std::unexpected(vtable.error());
}

auto obj_ptr =
runtime::AllocateObject(*vtable.value(), vtable_idx.value(), data.memory.object_repository, data.allocator);
auto obj_ptr = data.memory_manager.AllocateObject(*vtable.value(), vtable_idx.value(), data);

if (!obj_ptr) {
return std::unexpected(obj_ptr.error());
Expand Down Expand Up @@ -1452,7 +1457,7 @@ std::expected<ExecutionResult, std::runtime_error> NullCoalesce(PassedExecutionD

if (*tested_result_data != nullptr) {
data.memory.machine_stack.pop();
data.memory.machine_stack.emplace(tested_result.value());
data.memory.machine_stack.emplace(*tested_result_data);
}

return ExecutionResult::kNormal;
Expand Down Expand Up @@ -1602,10 +1607,9 @@ std::expected<ExecutionResult, std::runtime_error> FormatDateTime(PassedExecutio
return std::unexpected(vtable_index_result.error());
}

auto string_obj_result = runtime::AllocateObject(*string_vtable,
static_cast<uint32_t>(vtable_index_result.value()),
data.memory.object_repository,
data.allocator);
auto string_obj_result =
data.memory_manager.AllocateObject(*string_vtable, static_cast<uint32_t>(vtable_index_result.value()), data);

if (!string_obj_result.has_value()) {
return std::unexpected(string_obj_result.error());
}
Expand Down Expand Up @@ -1659,8 +1663,9 @@ std::expected<ExecutionResult, std::runtime_error> ParseDateTime(PassedExecution
return std::unexpected(vtable_index_result.error());
}

auto int_obj_result = runtime::AllocateObject(
*int_vtable, static_cast<uint32_t>(vtable_index_result.value()), data.memory.object_repository, data.allocator);
auto int_obj_result =
data.memory_manager.AllocateObject(*int_vtable, static_cast<uint32_t>(vtable_index_result.value()), data);

if (!int_obj_result.has_value()) {
return std::unexpected(int_obj_result.error());
}
Expand Down Expand Up @@ -1821,10 +1826,8 @@ std::expected<ExecutionResult, std::runtime_error> ListDir(PassedExecutionData&
return std::unexpected(vtable_index_result.error());
}

auto string_array_obj_result = runtime::AllocateObject(*string_array_vtable,
static_cast<uint32_t>(vtable_index_result.value()),
data.memory.object_repository,
data.allocator);
auto string_array_obj_result = data.memory_manager.AllocateObject(
*string_array_vtable, static_cast<uint32_t>(vtable_index_result.value()), data);
if (!string_array_obj_result.has_value()) {
return std::unexpected(string_array_obj_result.error());
}
Expand All @@ -1847,10 +1850,9 @@ std::expected<ExecutionResult, std::runtime_error> ListDir(PassedExecutionData&
return std::unexpected(string_vtable_index_result.error());
}

auto string_obj_result = runtime::AllocateObject(*string_vtable,
static_cast<uint32_t>(string_vtable_index_result.value()),
data.memory.object_repository,
data.allocator);
auto string_obj_result = data.memory_manager.AllocateObject(
*string_vtable, static_cast<uint32_t>(string_vtable_index_result.value()), data);

if (!string_obj_result.has_value()) {
return std::unexpected(string_obj_result.error());
}
Expand Down Expand Up @@ -2068,20 +2070,36 @@ std::expected<ExecutionResult, std::runtime_error> SeedRandom(PassedExecutionDat
}

std::expected<ExecutionResult, std::runtime_error> GetMemoryUsage(PassedExecutionData& data) {
// Simple memory usage approximation
size_t memory_usage = 0;

// Stack size
memory_usage += data.memory.machine_stack.size() * sizeof(runtime::Variable);

auto stack_copy = data.memory.stack_frames;
// Local variables in all stack frames
while (!stack_copy.empty()) {
memory_usage += stack_copy.top().local_variables.size() * sizeof(runtime::Variable);
stack_copy.pop();
#ifdef _WIN32
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
memory_usage = static_cast<size_t>(pmc.WorkingSetSize);
} else {
return std::unexpected(std::runtime_error("GetMemoryUsage: failed to get process memory info"));
}
#elif __APPLE__
struct task_basic_info info {};
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, reinterpret_cast<task_info_t>(&info), &size);
if (kerr == KERN_SUCCESS) {
memory_usage = static_cast<size_t>(info.resident_size);
} else {
return std::unexpected(std::runtime_error("GetMemoryUsage: failed to get task memory info"));
}
#else
// Linux: Use getrusage() system call
struct rusage usage {};
constexpr size_t kBytesInRusageUnit = 1024;
if (getrusage(RUSAGE_SELF, &usage) != 0) {
return std::unexpected(std::runtime_error("GetMemoryUsage: getrusage() failed"));
}

// TODO counter for repositories
// ru_maxrss is the maximum resident set size in kilobytes
// Note: getrusage gives maximum usage, not current usage
memory_usage = static_cast<size_t>(usage.ru_maxrss) * kBytesInRusageUnit;
#endif

data.memory.machine_stack.emplace(static_cast<int64_t>(memory_usage));
return ExecutionResult::kNormal;
Expand All @@ -2094,8 +2112,10 @@ std::expected<ExecutionResult, std::runtime_error> GetPeakMemoryUsage(PassedExec

std::expected<ExecutionResult, std::runtime_error> ForceGarbageCollection(PassedExecutionData& data) {
// Simple garbage collection: remove unreachable objects
// This is a placeholder implementation
// data.memory.object_repository.CollectGarbage();
auto result = data.memory_manager.CollectGarbage(data);
if (!result.has_value()) {
return std::unexpected(result.error());
}
return ExecutionResult::kNormal;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/execution_tree/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ add_library(execution_tree STATIC
target_include_directories(execution_tree PUBLIC ${PROJECT_SOURCE_DIR})

target_link_libraries(execution_tree PUBLIC runtime)

if(WIN32)
target_link_libraries(execution_tree PRIVATE psapi)
endif()
6 changes: 6 additions & 0 deletions lib/execution_tree/Command.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ class Command : public IExecutable {
return std::unexpected(std::runtime_error(error_message));
}

auto gc_res = execution_data.memory_manager.CollectGarbageIfRequired(execution_data);

if (!gc_res) {
return std::unexpected(gc_res.error());
}

return result.value();
}

Expand Down
3 changes: 2 additions & 1 deletion lib/execution_tree/PassedExecutionData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <memory>
#include <ostream>

#include "lib/runtime/MemoryManager.hpp"
#include "lib/runtime/RuntimeMemory.hpp"
#include "lib/runtime/VirtualTableRepository.hpp"

Expand All @@ -16,7 +17,7 @@ struct PassedExecutionData {
runtime::RuntimeMemory& memory;
const runtime::VirtualTableRepository& virtual_table_repository;
const FunctionRepository& function_repository;
std::allocator<char> allocator;
runtime::MemoryManager& memory_manager;
std::istream& input_stream;
std::ostream& output_stream;
std::ostream& error_stream;
Expand Down
Loading