diff --git a/CMakeLists.txt b/CMakeLists.txt index aea8f33..459b24d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,12 @@ cmake_minimum_required(VERSION 3.16) +if (MSVC) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi /Od") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /DEBUG") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") +endif() + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -29,6 +36,7 @@ set(SOURCES src/cxx/ACSVM/ACSVM/Thread.cpp src/cxx/ACSVM/ACSVM/ThreadExec.cpp src/cxx/ACSVM/ACSVM/Tracer.cpp + src/cxx/CrtDebug.cpp ) add_library(HelionACS-obj OBJECT ${SOURCES}) diff --git a/src/cs/Executor.cs b/src/cs/Executor.cs index ca8c1f5..bfdb9ff 100644 --- a/src/cs/Executor.cs +++ b/src/cs/Executor.cs @@ -127,7 +127,7 @@ public unsafe ReadOnlySpan GetStringSpan(uint argIndex, uint index) } } -public abstract class Executor +public abstract class Executor : IDisposable { const int FixedBits = 16; const int FixedOne = 1 << FixedBits; @@ -142,6 +142,7 @@ public abstract class Executor unsafe readonly protected Interop.Executor* m_executor; private readonly List m_handles; + private bool m_disposed; public unsafe Executor() { @@ -155,12 +156,22 @@ public unsafe Executor() m_executor = Interop.Methods.MakeExecutor(callbacks, (void*)GCHandle.ToIntPtr(selfHandle)); } - ~Executor() + public void Dispose() { + PerformDispose(); + GC.SuppressFinalize(this); + } + + protected unsafe void PerformDispose() + { + if (m_disposed) + return; + + Interop.Methods.FreeExecutor(m_executor); foreach (var handle in m_handles) - { handle.Free(); - } + + m_disposed = true; } protected GCHandle AddHandle(object obj) { diff --git a/src/cxx/CrtDebug.cpp b/src/cxx/CrtDebug.cpp new file mode 100644 index 0000000..36b0479 --- /dev/null +++ b/src/cxx/CrtDebug.cpp @@ -0,0 +1,20 @@ +#ifdef _CRTDEBUGENABLE +#include +#include +#endif +#include "CrtDebug.hpp" + +static bool Init = false; + +void CrtDebugInit() +{ +#ifdef _CRTDEBUGENABLE + if (Init) + return; + + Init = true; + int flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flags |= _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag(flags); +#endif +} diff --git a/src/cxx/CrtDebug.hpp b/src/cxx/CrtDebug.hpp new file mode 100644 index 0000000..afbbc6b --- /dev/null +++ b/src/cxx/CrtDebug.hpp @@ -0,0 +1,3 @@ +#pragma once + +void CrtDebugInit(); \ No newline at end of file diff --git a/src/cxx/HelionACS.cpp b/src/cxx/HelionACS.cpp index 87e6748..7d672e7 100644 --- a/src/cxx/HelionACS.cpp +++ b/src/cxx/HelionACS.cpp @@ -13,6 +13,7 @@ #include "ACSVM/ACSVM/MemorySerial.hpp" #include "ACSVM/ACSVM/Error.hpp" #include "ACSVM/ACSVM/Stack.hpp" +#include "CrtDebug.hpp" #include #include #include @@ -88,6 +89,7 @@ class Env : public ACSVM::Environment { void loadModule(ACSVM::Module *module) override { auto data = this->callbacks.loadModuleCallback(this->executorContext, module->name.s->str, module->name.s->len); module->readBytecode(data.data, data.length); + delete[] data.data; } ACSVM::Word callSpecImpl(ACSVM::Thread *thread, ACSVM::Word spec, const ACSVM::Word *argV, ACSVM::Word argC) override { return this->callbacks.callSpecImplCallback(this->executorContext, thread, spec, argV, argC); @@ -131,7 +133,8 @@ class Executor { Executor(Callbacks callbacks, void* executorContext) : env(callbacks, executorContext) {} void LoadHubMap(ACSVM::Word hubId, ACSVM::Word mapId, std::span moduleNames) { - auto global = env.getGlobalScope(0); global->active = true; + auto global = env.getGlobalScope(0); + global->active = true; if ( hubId != 0 @@ -145,12 +148,14 @@ class Executor { this->env.currentHubScope = nullptr; env.currentMapScope = nullptr; } - this->env.currentHubScope = global->getHubScope(hubId); this->env.currentHubScope->active = true; + this->env.currentHubScope = global->getHubScope(hubId); + this->env.currentHubScope->active = true; if (this->env.currentMapScope != nullptr && this->env.currentMapScope->id != mapId) { this->env.currentMapScope->active = false; this->env.currentMapScope = nullptr; } - this->env.currentMapScope = this->env.currentHubScope->getMapScope(mapId); this->env.currentMapScope->active = true; + this->env.currentMapScope = this->env.currentHubScope->getMapScope(mapId); + this->env.currentMapScope->active = true; if (!this->env.currentMapScope->hasModules()) { auto modules = std::vector {}; @@ -162,14 +167,14 @@ class Executor { } } - ACSVM::MapScope::ScriptStartInfo MakeInfo(CSThreadInfo info, ACSVM::Word* argV, std::size_t argC) { + ACSVM::MapScope::ScriptStartInfo MakeInfo(IndexThreadInfo* indexThreadInfo, ACSVM::Word* argV, std::size_t argC) { auto actualInfo = ACSVM::MapScope::ScriptStartInfo {}; actualInfo.argV = argV; actualInfo.argC = argC; - auto threadInfo = new IndexThreadInfo(info); - actualInfo.info = threadInfo; + actualInfo.info = indexThreadInfo; return actualInfo; } + ACSVM::ScriptName GetScriptName(ACSVM::Word scriptId) { return ACSVM::ScriptName(scriptId); } @@ -183,26 +188,31 @@ class Executor { ACSVM::Word ScriptStartType(ACSVM::Word type, ACSVM::Word* argV, std::size_t argC, CSThreadInfo info) { if (this->env.currentMapScope == nullptr) { return 0; } - return this->env.currentMapScope->scriptStartType(type, this->MakeInfo(info, argV, argC)); + IndexThreadInfo indexThreadInfo(info); + return this->env.currentMapScope->scriptStartType(type, this->MakeInfo(&indexThreadInfo, argV, argC)); } ACSVM::Word ScriptStartTypeForced(ACSVM::Word type, ACSVM::Word* argV, std::size_t argC, CSThreadInfo info) { if (this->env.currentMapScope == nullptr) { return 0; } - return this->env.currentMapScope->scriptStartTypeForced(type, this->MakeInfo(info, argV, argC)); + IndexThreadInfo indexThreadInfo(info); + return this->env.currentMapScope->scriptStartTypeForced(type, this->MakeInfo(&indexThreadInfo, argV, argC)); } template bool ScriptStart(T scriptId, ACSVM::Word hubId, ACSVM::Word mapId, ACSVM::Word* argV, std::size_t argC, CSThreadInfo info) { if (this->env.currentMapScope == nullptr) { return false; } - return this->env.currentMapScope->scriptStart(this->GetScriptName(scriptId), this->GetScope(hubId, mapId), this->MakeInfo(info, argV, argC)); + IndexThreadInfo indexThreadInfo(info); + return this->env.currentMapScope->scriptStart(this->GetScriptName(scriptId), this->GetScope(hubId, mapId), this->MakeInfo(&indexThreadInfo, argV, argC)); } template bool ScriptStartForced(T scriptId, ACSVM::Word hubId, ACSVM::Word mapId, ACSVM::Word* argV, std::size_t argC, CSThreadInfo info) { if (this->env.currentMapScope == nullptr) { return false; } - return this->env.currentMapScope->scriptStartForced(this->GetScriptName(scriptId), this->GetScope(hubId, mapId), this->MakeInfo(info, argV, argC)); + IndexThreadInfo indexThreadInfo(info); + return this->env.currentMapScope->scriptStartForced(this->GetScriptName(scriptId), this->GetScope(hubId, mapId), this->MakeInfo(&indexThreadInfo, argV, argC)); } template ACSVM::Word ScriptStartResult(T scriptId, ACSVM::Word* argV, std::size_t argC, CSThreadInfo info) { if (this->env.currentMapScope == nullptr) { return 0; } - return this->env.currentMapScope->scriptStartResult(this->GetScriptName(scriptId), this->MakeInfo(info, argV, argC)); + IndexThreadInfo indexThreadInfo(info); + return this->env.currentMapScope->scriptStartResult(this->GetScriptName(scriptId), this->MakeInfo(&indexThreadInfo, argV, argC)); } template bool ScriptStop(T scriptId, ACSVM::Word hubId, ACSVM::Word mapId) { @@ -309,15 +319,19 @@ class Executor { }; ModuleData MakeModuleData(std::size_t length) { - ModuleData ret; + ModuleData ret{}; ret.data = (length != 0) ? (new ACSVM::Byte[length] { 0 }) : nullptr; ret.length = length; return ret; } Executor* MakeExecutor(Callbacks callbacks, void* executorContext) { + CrtDebugInit(); return new Executor(callbacks, executorContext); } +void FreeExecutor(Executor* executor) { + delete executor; +} void LoadHubMap( Executor* executor, ACSVM::Word hubId, diff --git a/src/cxx/HelionACS.hpp b/src/cxx/HelionACS.hpp index f152a41..d256519 100644 --- a/src/cxx/HelionACS.hpp +++ b/src/cxx/HelionACS.hpp @@ -29,6 +29,7 @@ struct Callbacks { class Executor; HELIONACS_API Executor* MakeExecutor(Callbacks callbacks, void* executorContext); +HELIONACS_API void FreeExecutor(Executor* executor); struct CSThreadInfo { int32_t activator; int32_t line;